xref: /linux/drivers/gpu/drm/xe/xe_guc_capture.c (revision 8bfc496327ce0f3bd02445048e3a70cc97accc6d)
19c8c7a7eSZhanjun Dong // SPDX-License-Identifier: MIT
29c8c7a7eSZhanjun Dong /*
39c8c7a7eSZhanjun Dong  * Copyright © 2021-2024 Intel Corporation
49c8c7a7eSZhanjun Dong  */
59c8c7a7eSZhanjun Dong 
69c8c7a7eSZhanjun Dong #include <linux/types.h>
79c8c7a7eSZhanjun Dong 
89c8c7a7eSZhanjun Dong #include <drm/drm_managed.h>
99c8c7a7eSZhanjun Dong #include <drm/drm_print.h>
109c8c7a7eSZhanjun Dong 
119c8c7a7eSZhanjun Dong #include "abi/guc_actions_abi.h"
129c8c7a7eSZhanjun Dong #include "abi/guc_capture_abi.h"
13*8bfc4963SZhanjun Dong #include "abi/guc_log_abi.h"
149c8c7a7eSZhanjun Dong #include "regs/xe_engine_regs.h"
159c8c7a7eSZhanjun Dong #include "regs/xe_gt_regs.h"
169c8c7a7eSZhanjun Dong #include "regs/xe_guc_regs.h"
179c8c7a7eSZhanjun Dong #include "regs/xe_regs.h"
189c8c7a7eSZhanjun Dong 
199c8c7a7eSZhanjun Dong #include "xe_bo.h"
209c8c7a7eSZhanjun Dong #include "xe_device.h"
219c8c7a7eSZhanjun Dong #include "xe_exec_queue_types.h"
229c8c7a7eSZhanjun Dong #include "xe_gt.h"
239c8c7a7eSZhanjun Dong #include "xe_gt_mcr.h"
249c8c7a7eSZhanjun Dong #include "xe_gt_printk.h"
259c8c7a7eSZhanjun Dong #include "xe_guc.h"
2684d15f42SZhanjun Dong #include "xe_guc_ads.h"
279c8c7a7eSZhanjun Dong #include "xe_guc_capture.h"
289c8c7a7eSZhanjun Dong #include "xe_guc_capture_types.h"
299c8c7a7eSZhanjun Dong #include "xe_guc_ct.h"
309c8c7a7eSZhanjun Dong #include "xe_guc_log.h"
319c8c7a7eSZhanjun Dong #include "xe_guc_submit.h"
329c8c7a7eSZhanjun Dong #include "xe_hw_engine_types.h"
339c8c7a7eSZhanjun Dong #include "xe_macros.h"
349c8c7a7eSZhanjun Dong #include "xe_map.h"
359c8c7a7eSZhanjun Dong 
369c8c7a7eSZhanjun Dong /*
37*8bfc4963SZhanjun Dong  * struct __guc_capture_bufstate
38*8bfc4963SZhanjun Dong  *
39*8bfc4963SZhanjun Dong  * Book-keeping structure used to track read and write pointers
40*8bfc4963SZhanjun Dong  * as we extract error capture data from the GuC-log-buffer's
41*8bfc4963SZhanjun Dong  * error-capture region as a stream of dwords.
42*8bfc4963SZhanjun Dong  */
43*8bfc4963SZhanjun Dong struct __guc_capture_bufstate {
44*8bfc4963SZhanjun Dong 	u32 size;
45*8bfc4963SZhanjun Dong 	u32 data_offset;
46*8bfc4963SZhanjun Dong 	u32 rd;
47*8bfc4963SZhanjun Dong 	u32 wr;
48*8bfc4963SZhanjun Dong };
49*8bfc4963SZhanjun Dong 
50*8bfc4963SZhanjun Dong /*
51*8bfc4963SZhanjun Dong  * struct __guc_capture_parsed_output - extracted error capture node
52*8bfc4963SZhanjun Dong  *
53*8bfc4963SZhanjun Dong  * A single unit of extracted error-capture output data grouped together
54*8bfc4963SZhanjun Dong  * at an engine-instance level. We keep these nodes in a linked list.
55*8bfc4963SZhanjun Dong  * See cachelist and outlist below.
56*8bfc4963SZhanjun Dong  */
57*8bfc4963SZhanjun Dong struct __guc_capture_parsed_output {
58*8bfc4963SZhanjun Dong 	/*
59*8bfc4963SZhanjun Dong 	 * A single set of 3 capture lists: a global-list
60*8bfc4963SZhanjun Dong 	 * an engine-class-list and an engine-instance list.
61*8bfc4963SZhanjun Dong 	 * outlist in __guc_capture_parsed_output will keep
62*8bfc4963SZhanjun Dong 	 * a linked list of these nodes that will eventually
63*8bfc4963SZhanjun Dong 	 * be detached from outlist and attached into to
64*8bfc4963SZhanjun Dong 	 * xe_codedump in response to a context reset
65*8bfc4963SZhanjun Dong 	 */
66*8bfc4963SZhanjun Dong 	struct list_head link;
67*8bfc4963SZhanjun Dong 	bool is_partial;
68*8bfc4963SZhanjun Dong 	u32 eng_class;
69*8bfc4963SZhanjun Dong 	u32 eng_inst;
70*8bfc4963SZhanjun Dong 	u32 guc_id;
71*8bfc4963SZhanjun Dong 	u32 lrca;
72*8bfc4963SZhanjun Dong 	struct gcap_reg_list_info {
73*8bfc4963SZhanjun Dong 		u32 vfid;
74*8bfc4963SZhanjun Dong 		u32 num_regs;
75*8bfc4963SZhanjun Dong 		struct guc_mmio_reg *regs;
76*8bfc4963SZhanjun Dong 	} reginfo[GUC_STATE_CAPTURE_TYPE_MAX];
77*8bfc4963SZhanjun Dong #define GCAP_PARSED_REGLIST_INDEX_GLOBAL   BIT(GUC_STATE_CAPTURE_TYPE_GLOBAL)
78*8bfc4963SZhanjun Dong #define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS)
79*8bfc4963SZhanjun Dong };
80*8bfc4963SZhanjun Dong 
81*8bfc4963SZhanjun Dong /*
829c8c7a7eSZhanjun Dong  * Define all device tables of GuC error capture register lists
839c8c7a7eSZhanjun Dong  * NOTE:
849c8c7a7eSZhanjun Dong  *     For engine-registers, GuC only needs the register offsets
859c8c7a7eSZhanjun Dong  *     from the engine-mmio-base
869c8c7a7eSZhanjun Dong  *
879c8c7a7eSZhanjun Dong  *     64 bit registers need 2 entries for low 32 bit register and high 32 bit
889c8c7a7eSZhanjun Dong  *     register, for example:
899c8c7a7eSZhanjun Dong  *       Register           data_type       flags   mask    Register name
909c8c7a7eSZhanjun Dong  *     { XXX_REG_LO(0),  REG_64BIT_LOW_DW,    0,      0,      NULL},
919c8c7a7eSZhanjun Dong  *     { XXX_REG_HI(0),  REG_64BIT_HI_DW,,    0,      0,      "XXX_REG"},
929c8c7a7eSZhanjun Dong  *     1. data_type: Indicate is hi/low 32 bit for a 64 bit register
939c8c7a7eSZhanjun Dong  *                   A 64 bit register define requires 2 consecutive entries,
949c8c7a7eSZhanjun Dong  *                   with low dword first and hi dword the second.
959c8c7a7eSZhanjun Dong  *     2. Register name: null for incompleted define
969c8c7a7eSZhanjun Dong  */
979c8c7a7eSZhanjun Dong #define COMMON_XELP_BASE_GLOBAL \
989c8c7a7eSZhanjun Dong 	{ FORCEWAKE_GT,			REG_32BIT,	0,	0,	"FORCEWAKE_GT"}
999c8c7a7eSZhanjun Dong 
1009c8c7a7eSZhanjun Dong #define COMMON_BASE_ENGINE_INSTANCE \
1019c8c7a7eSZhanjun Dong 	{ RING_HWSTAM(0),		REG_32BIT,	0,	0,	"HWSTAM"}, \
1029c8c7a7eSZhanjun Dong 	{ RING_HWS_PGA(0),		REG_32BIT,	0,	0,	"RING_HWS_PGA"}, \
1039c8c7a7eSZhanjun Dong 	{ RING_HEAD(0),			REG_32BIT,	0,	0,	"RING_HEAD"}, \
1049c8c7a7eSZhanjun Dong 	{ RING_TAIL(0),			REG_32BIT,	0,	0,	"RING_TAIL"}, \
1059c8c7a7eSZhanjun Dong 	{ RING_CTL(0),			REG_32BIT,	0,	0,	"RING_CTL"}, \
1069c8c7a7eSZhanjun Dong 	{ RING_MI_MODE(0),		REG_32BIT,	0,	0,	"RING_MI_MODE"}, \
1079c8c7a7eSZhanjun Dong 	{ RING_MODE(0),			REG_32BIT,	0,	0,	"RING_MODE"}, \
1089c8c7a7eSZhanjun Dong 	{ RING_ESR(0),			REG_32BIT,	0,	0,	"RING_ESR"}, \
1099c8c7a7eSZhanjun Dong 	{ RING_EMR(0),			REG_32BIT,	0,	0,	"RING_EMR"}, \
1109c8c7a7eSZhanjun Dong 	{ RING_EIR(0),			REG_32BIT,	0,	0,	"RING_EIR"}, \
1119c8c7a7eSZhanjun Dong 	{ RING_IMR(0),			REG_32BIT,	0,	0,	"RING_IMR"}, \
1129c8c7a7eSZhanjun Dong 	{ RING_IPEHR(0),		REG_32BIT,	0,	0,	"IPEHR"}, \
1139c8c7a7eSZhanjun Dong 	{ RING_INSTDONE(0),		REG_32BIT,	0,	0,	"RING_INSTDONE"}, \
1149c8c7a7eSZhanjun Dong 	{ INDIRECT_RING_STATE(0),	REG_32BIT,	0,	0,	"INDIRECT_RING_STATE"}, \
1159c8c7a7eSZhanjun Dong 	{ RING_ACTHD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1169c8c7a7eSZhanjun Dong 	{ RING_ACTHD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"ACTHD"}, \
1179c8c7a7eSZhanjun Dong 	{ RING_BBADDR(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1189c8c7a7eSZhanjun Dong 	{ RING_BBADDR_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_BBADDR"}, \
1199c8c7a7eSZhanjun Dong 	{ RING_START(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1209c8c7a7eSZhanjun Dong 	{ RING_START_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_START"}, \
1219c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1229c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_DMA_FADD"}, \
1239c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_LO(0),	REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1249c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_HI(0),	REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_STATUS"}, \
1259c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0,	0,	NULL}, \
1269c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_SQ_CONTENTS"}
1279c8c7a7eSZhanjun Dong 
1289c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS \
1299c8c7a7eSZhanjun Dong 	{ RCU_MODE,			REG_32BIT,	0,	0,	"RCU_MODE"}
1309c8c7a7eSZhanjun Dong 
1319c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS_INSTDONE \
1329c8c7a7eSZhanjun Dong 	{ SC_INSTDONE,			REG_32BIT,	0,	0,	"SC_INSTDONE"}, \
1339c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA"}, \
1349c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA2,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA2"}
1359c8c7a7eSZhanjun Dong 
1369c8c7a7eSZhanjun Dong #define XELP_VEC_CLASS_REGS \
1379c8c7a7eSZhanjun Dong 	{ SFC_DONE(0),			0,	0,	0,	"SFC_DONE[0]"}, \
1389c8c7a7eSZhanjun Dong 	{ SFC_DONE(1),			0,	0,	0,	"SFC_DONE[1]"}, \
1399c8c7a7eSZhanjun Dong 	{ SFC_DONE(2),			0,	0,	0,	"SFC_DONE[2]"}, \
1409c8c7a7eSZhanjun Dong 	{ SFC_DONE(3),			0,	0,	0,	"SFC_DONE[3]"}
1419c8c7a7eSZhanjun Dong 
1429c8c7a7eSZhanjun Dong /* XE_LP Global */
1439c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
1449c8c7a7eSZhanjun Dong 	COMMON_XELP_BASE_GLOBAL,
1459c8c7a7eSZhanjun Dong };
1469c8c7a7eSZhanjun Dong 
1479c8c7a7eSZhanjun Dong /* Render / Compute Per-Engine-Instance */
1489c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = {
1499c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1509c8c7a7eSZhanjun Dong };
1519c8c7a7eSZhanjun Dong 
1529c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class */
1539c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = {
1549c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
1559c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS_INSTDONE,
1569c8c7a7eSZhanjun Dong };
1579c8c7a7eSZhanjun Dong 
1589c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class for xehpg */
1599c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = {
1609c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
1619c8c7a7eSZhanjun Dong };
1629c8c7a7eSZhanjun Dong 
1639c8c7a7eSZhanjun Dong /* Media Decode/Encode Per-Engine-Instance */
1649c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = {
1659c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1669c8c7a7eSZhanjun Dong };
1679c8c7a7eSZhanjun Dong 
1689c8c7a7eSZhanjun Dong /* Video Enhancement Engine-Class */
1699c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = {
1709c8c7a7eSZhanjun Dong 	XELP_VEC_CLASS_REGS,
1719c8c7a7eSZhanjun Dong };
1729c8c7a7eSZhanjun Dong 
1739c8c7a7eSZhanjun Dong /* Video Enhancement Per-Engine-Instance */
1749c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = {
1759c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1769c8c7a7eSZhanjun Dong };
1779c8c7a7eSZhanjun Dong 
1789c8c7a7eSZhanjun Dong /* Blitter Per-Engine-Instance */
1799c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = {
1809c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1819c8c7a7eSZhanjun Dong };
1829c8c7a7eSZhanjun Dong 
1839c8c7a7eSZhanjun Dong /* XE_LP - GSC Per-Engine-Instance */
1849c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {
1859c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1869c8c7a7eSZhanjun Dong };
1879c8c7a7eSZhanjun Dong 
1889c8c7a7eSZhanjun Dong /*
1899c8c7a7eSZhanjun Dong  * Empty list to prevent warnings about unknown class/instance types
1909c8c7a7eSZhanjun Dong  * as not all class/instance types have entries on all platforms.
1919c8c7a7eSZhanjun Dong  */
1929c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr empty_regs_list[] = {
1939c8c7a7eSZhanjun Dong };
1949c8c7a7eSZhanjun Dong 
1959c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
1969c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x)
1979c8c7a7eSZhanjun Dong #define MAKE_REGLIST(regslist, regsowner, regstype, class) \
1989c8c7a7eSZhanjun Dong 	{ \
1999c8c7a7eSZhanjun Dong 		regslist, \
2009c8c7a7eSZhanjun Dong 		ARRAY_SIZE(regslist), \
2019c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_OWNER(regsowner), \
2029c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_TYPE(regstype), \
2039c8c7a7eSZhanjun Dong 		class \
2049c8c7a7eSZhanjun Dong 	}
2059c8c7a7eSZhanjun Dong 
2069c8c7a7eSZhanjun Dong /* List of lists for legacy graphic product version < 1255 */
2079c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {
2089c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
2099c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2109c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2119c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
2129c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
2139c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2149c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2159c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
2169c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
2179c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2189c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2199c8c7a7eSZhanjun Dong 	{}
2209c8c7a7eSZhanjun Dong };
2219c8c7a7eSZhanjun Dong 
2229c8c7a7eSZhanjun Dong  /* List of lists for graphic product version >= 1255 */
2239c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = {
2249c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
2259c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2269c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2279c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
2289c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
2299c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2309c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2319c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
2329c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
2339c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2349c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2359c8c7a7eSZhanjun Dong 	{}
2369c8c7a7eSZhanjun Dong };
2379c8c7a7eSZhanjun Dong 
2389c8c7a7eSZhanjun Dong static const char * const capture_list_type_names[] = {
2399c8c7a7eSZhanjun Dong 	"Global",
2409c8c7a7eSZhanjun Dong 	"Class",
2419c8c7a7eSZhanjun Dong 	"Instance",
2429c8c7a7eSZhanjun Dong };
2439c8c7a7eSZhanjun Dong 
2449c8c7a7eSZhanjun Dong static const char * const capture_engine_class_names[] = {
2459c8c7a7eSZhanjun Dong 	"Render/Compute",
2469c8c7a7eSZhanjun Dong 	"Video",
2479c8c7a7eSZhanjun Dong 	"VideoEnhance",
2489c8c7a7eSZhanjun Dong 	"Blitter",
2499c8c7a7eSZhanjun Dong 	"GSC-Other",
2509c8c7a7eSZhanjun Dong };
2519c8c7a7eSZhanjun Dong 
2529c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache {
2539c8c7a7eSZhanjun Dong 	bool is_valid;
2549c8c7a7eSZhanjun Dong 	void *ptr;
2559c8c7a7eSZhanjun Dong 	size_t size;
2569c8c7a7eSZhanjun Dong 	int status;
2579c8c7a7eSZhanjun Dong };
2589c8c7a7eSZhanjun Dong 
2599c8c7a7eSZhanjun Dong struct xe_guc_state_capture {
2609c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists;
261b170d696SZhanjun Dong 	/**
262b170d696SZhanjun Dong 	 * NOTE: steered registers have multiple instances depending on the HW configuration
263b170d696SZhanjun Dong 	 * (slices or dual-sub-slices) and thus depends on HW fuses discovered
264b170d696SZhanjun Dong 	 */
265b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists;
2669c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
2679c8c7a7eSZhanjun Dong 						[GUC_STATE_CAPTURE_TYPE_MAX]
2689c8c7a7eSZhanjun Dong 						[GUC_CAPTURE_LIST_CLASS_MAX];
2699c8c7a7eSZhanjun Dong 	void *ads_null_cache;
270*8bfc4963SZhanjun Dong 	struct list_head cachelist;
271*8bfc4963SZhanjun Dong #define PREALLOC_NODES_MAX_COUNT (3 * GUC_MAX_ENGINE_CLASSES * GUC_MAX_INSTANCES_PER_CLASS)
272*8bfc4963SZhanjun Dong #define PREALLOC_NODES_DEFAULT_NUMREGS 64
273*8bfc4963SZhanjun Dong 
274*8bfc4963SZhanjun Dong 	int max_mmio_per_node;
275*8bfc4963SZhanjun Dong 	struct list_head outlist;
2769c8c7a7eSZhanjun Dong };
2779c8c7a7eSZhanjun Dong 
2789c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
2799c8c7a7eSZhanjun Dong guc_capture_get_device_reglist(struct xe_device *xe)
2809c8c7a7eSZhanjun Dong {
2819c8c7a7eSZhanjun Dong 	if (GRAPHICS_VERx100(xe) >= 1255)
2829c8c7a7eSZhanjun Dong 		return xe_hpg_lists;
2839c8c7a7eSZhanjun Dong 	else
2849c8c7a7eSZhanjun Dong 		return xe_lp_lists;
2859c8c7a7eSZhanjun Dong }
2869c8c7a7eSZhanjun Dong 
2879c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
2889c8c7a7eSZhanjun Dong guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
2899c8c7a7eSZhanjun Dong 			 u32 owner, u32 type, enum guc_capture_list_class_type capture_class)
2909c8c7a7eSZhanjun Dong {
2919c8c7a7eSZhanjun Dong 	int i;
2929c8c7a7eSZhanjun Dong 
2939c8c7a7eSZhanjun Dong 	if (!reglists)
2949c8c7a7eSZhanjun Dong 		return NULL;
2959c8c7a7eSZhanjun Dong 
2969c8c7a7eSZhanjun Dong 	for (i = 0; reglists[i].list; ++i) {
2979c8c7a7eSZhanjun Dong 		if (reglists[i].owner == owner && reglists[i].type == type &&
2989c8c7a7eSZhanjun Dong 		    (reglists[i].engine == capture_class ||
2999c8c7a7eSZhanjun Dong 		     reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL))
3009c8c7a7eSZhanjun Dong 			return &reglists[i];
3019c8c7a7eSZhanjun Dong 	}
3029c8c7a7eSZhanjun Dong 
3039c8c7a7eSZhanjun Dong 	return NULL;
3049c8c7a7eSZhanjun Dong }
3059c8c7a7eSZhanjun Dong 
306b170d696SZhanjun Dong struct __ext_steer_reg {
307b170d696SZhanjun Dong 	const char *name;
308b170d696SZhanjun Dong 	struct xe_reg_mcr reg;
309b170d696SZhanjun Dong };
310b170d696SZhanjun Dong 
311b170d696SZhanjun Dong static const struct __ext_steer_reg xe_extregs[] = {
312b170d696SZhanjun Dong 	{"SAMPLER_INSTDONE",		SAMPLER_INSTDONE},
313b170d696SZhanjun Dong 	{"ROW_INSTDONE",		ROW_INSTDONE}
314b170d696SZhanjun Dong };
315b170d696SZhanjun Dong 
316b170d696SZhanjun Dong static const struct __ext_steer_reg xehpg_extregs[] = {
317b170d696SZhanjun Dong 	{"SC_INSTDONE",			XEHPG_SC_INSTDONE},
318b170d696SZhanjun Dong 	{"SC_INSTDONE_EXTRA",		XEHPG_SC_INSTDONE_EXTRA},
319b170d696SZhanjun Dong 	{"SC_INSTDONE_EXTRA2",		XEHPG_SC_INSTDONE_EXTRA2},
320b170d696SZhanjun Dong 	{"INSTDONE_GEOM_SVGUNIT",	XEHPG_INSTDONE_GEOM_SVGUNIT}
321b170d696SZhanjun Dong };
322b170d696SZhanjun Dong 
323b170d696SZhanjun Dong static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
324b170d696SZhanjun Dong 			   const struct __ext_steer_reg *extlist,
325b170d696SZhanjun Dong 			   int slice_id, int subslice_id)
326b170d696SZhanjun Dong {
327b170d696SZhanjun Dong 	if (!ext || !extlist)
328b170d696SZhanjun Dong 		return;
329b170d696SZhanjun Dong 
330b170d696SZhanjun Dong 	ext->reg = XE_REG(extlist->reg.__reg.addr);
331b170d696SZhanjun Dong 	ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1);
332b170d696SZhanjun Dong 	ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
333b170d696SZhanjun Dong 	ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
334b170d696SZhanjun Dong 	ext->regname = extlist->name;
335b170d696SZhanjun Dong }
336b170d696SZhanjun Dong 
337b170d696SZhanjun Dong static int
338b170d696SZhanjun Dong __alloc_ext_regs(struct drm_device *drm, struct __guc_mmio_reg_descr_group *newlist,
339b170d696SZhanjun Dong 		 const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)
340b170d696SZhanjun Dong {
341b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr *list;
342b170d696SZhanjun Dong 
343b170d696SZhanjun Dong 	list = drmm_kzalloc(drm, num_regs * sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
344b170d696SZhanjun Dong 	if (!list)
345b170d696SZhanjun Dong 		return -ENOMEM;
346b170d696SZhanjun Dong 
347b170d696SZhanjun Dong 	newlist->list = list;
348b170d696SZhanjun Dong 	newlist->num_regs = num_regs;
349b170d696SZhanjun Dong 	newlist->owner = rootlist->owner;
350b170d696SZhanjun Dong 	newlist->engine = rootlist->engine;
351b170d696SZhanjun Dong 	newlist->type = rootlist->type;
352b170d696SZhanjun Dong 
353b170d696SZhanjun Dong 	return 0;
354b170d696SZhanjun Dong }
355b170d696SZhanjun Dong 
356b170d696SZhanjun Dong static int guc_capture_get_steer_reg_num(struct xe_device *xe)
357b170d696SZhanjun Dong {
358b170d696SZhanjun Dong 	int num = ARRAY_SIZE(xe_extregs);
359b170d696SZhanjun Dong 
360b170d696SZhanjun Dong 	if (GRAPHICS_VERx100(xe) >= 1255)
361b170d696SZhanjun Dong 		num += ARRAY_SIZE(xehpg_extregs);
362b170d696SZhanjun Dong 
363b170d696SZhanjun Dong 	return num;
364b170d696SZhanjun Dong }
365b170d696SZhanjun Dong 
366b170d696SZhanjun Dong static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
367b170d696SZhanjun Dong {
368b170d696SZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
369b170d696SZhanjun Dong 	u16 slice, subslice;
370b170d696SZhanjun Dong 	int iter, i, total = 0;
371b170d696SZhanjun Dong 	const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists;
372b170d696SZhanjun Dong 	const struct __guc_mmio_reg_descr_group *list;
373b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists;
374b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr *extarray;
375b170d696SZhanjun Dong 	bool has_xehpg_extregs = GRAPHICS_VERx100(gt_to_xe(gt)) >= 1255;
376b170d696SZhanjun Dong 	struct drm_device *drm = &gt_to_xe(gt)->drm;
377b170d696SZhanjun Dong 	bool has_rcs_ccs = false;
378b170d696SZhanjun Dong 	struct xe_hw_engine *hwe;
379b170d696SZhanjun Dong 	enum xe_hw_engine_id id;
380b170d696SZhanjun Dong 
381b170d696SZhanjun Dong 	/*
382b170d696SZhanjun Dong 	 * If GT has no rcs/ccs, no need to alloc steered list.
383b170d696SZhanjun Dong 	 * Currently, only rcs/ccs has steering register, if in the future,
384b170d696SZhanjun Dong 	 * other engine types has steering register, this condition check need
385b170d696SZhanjun Dong 	 * to be extended
386b170d696SZhanjun Dong 	 */
387b170d696SZhanjun Dong 	for_each_hw_engine(hwe, gt, id) {
388b170d696SZhanjun Dong 		if (xe_engine_class_to_guc_capture_class(hwe->class) ==
389b170d696SZhanjun Dong 		    GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
390b170d696SZhanjun Dong 			has_rcs_ccs = true;
391b170d696SZhanjun Dong 			break;
392b170d696SZhanjun Dong 		}
393b170d696SZhanjun Dong 	}
394b170d696SZhanjun Dong 
395b170d696SZhanjun Dong 	if (!has_rcs_ccs)
396b170d696SZhanjun Dong 		return;
397b170d696SZhanjun Dong 
398b170d696SZhanjun Dong 	/* steered registers currently only exist for the render-class */
399b170d696SZhanjun Dong 	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
400b170d696SZhanjun Dong 					GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
401b170d696SZhanjun Dong 					GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE);
402b170d696SZhanjun Dong 	/*
403b170d696SZhanjun Dong 	 * Skip if this platform has no engine class registers or if extlists
404b170d696SZhanjun Dong 	 * was previously allocated
405b170d696SZhanjun Dong 	 */
406b170d696SZhanjun Dong 	if (!list || guc->capture->extlists)
407b170d696SZhanjun Dong 		return;
408b170d696SZhanjun Dong 
409b170d696SZhanjun Dong 	total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) *
410b170d696SZhanjun Dong 		guc_capture_get_steer_reg_num(guc_to_xe(guc));
411b170d696SZhanjun Dong 
412b170d696SZhanjun Dong 	if (!total)
413b170d696SZhanjun Dong 		return;
414b170d696SZhanjun Dong 
415b170d696SZhanjun Dong 	/* allocate an extra for an end marker */
416b170d696SZhanjun Dong 	extlists = drmm_kzalloc(drm, 2 * sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL);
417b170d696SZhanjun Dong 	if (!extlists)
418b170d696SZhanjun Dong 		return;
419b170d696SZhanjun Dong 
420b170d696SZhanjun Dong 	if (__alloc_ext_regs(drm, &extlists[0], list, total)) {
421b170d696SZhanjun Dong 		drmm_kfree(drm, extlists);
422b170d696SZhanjun Dong 		return;
423b170d696SZhanjun Dong 	}
424b170d696SZhanjun Dong 
425b170d696SZhanjun Dong 	/* For steering registers, the list is generated at run-time */
426b170d696SZhanjun Dong 	extarray = (struct __guc_mmio_reg_descr *)extlists[0].list;
427b170d696SZhanjun Dong 	for_each_dss_steering(iter, gt, slice, subslice) {
428b170d696SZhanjun Dong 		for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) {
429b170d696SZhanjun Dong 			__fill_ext_reg(extarray, &xe_extregs[i], slice, subslice);
430b170d696SZhanjun Dong 			++extarray;
431b170d696SZhanjun Dong 		}
432b170d696SZhanjun Dong 
433b170d696SZhanjun Dong 		if (has_xehpg_extregs)
434b170d696SZhanjun Dong 			for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {
435b170d696SZhanjun Dong 				__fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice);
436b170d696SZhanjun Dong 				++extarray;
437b170d696SZhanjun Dong 			}
438b170d696SZhanjun Dong 	}
439b170d696SZhanjun Dong 
440b170d696SZhanjun Dong 	extlists[0].num_regs = total;
441b170d696SZhanjun Dong 
442b170d696SZhanjun Dong 	xe_gt_dbg(guc_to_gt(guc), "capture found %d ext-regs.\n", total);
443b170d696SZhanjun Dong 	guc->capture->extlists = extlists;
444b170d696SZhanjun Dong }
445b170d696SZhanjun Dong 
4469c8c7a7eSZhanjun Dong static int
4479c8c7a7eSZhanjun Dong guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
4489c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr,
4499c8c7a7eSZhanjun Dong 		      u16 num_entries)
4509c8c7a7eSZhanjun Dong {
451b170d696SZhanjun Dong 	u32 ptr_idx = 0, list_idx = 0;
4529c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
453b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;
4549c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
455b170d696SZhanjun Dong 	u32 list_num;
4569c8c7a7eSZhanjun Dong 
4579c8c7a7eSZhanjun Dong 	if (!reglists)
4589c8c7a7eSZhanjun Dong 		return -ENODEV;
4599c8c7a7eSZhanjun Dong 
4609c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(reglists, owner, type, capture_class);
4619c8c7a7eSZhanjun Dong 	if (!match)
4629c8c7a7eSZhanjun Dong 		return -ENODATA;
4639c8c7a7eSZhanjun Dong 
464b170d696SZhanjun Dong 	list_num = match->num_regs;
465b170d696SZhanjun Dong 	for (list_idx = 0; ptr_idx < num_entries && list_idx < list_num; ++list_idx, ++ptr_idx) {
466b170d696SZhanjun Dong 		ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
467b170d696SZhanjun Dong 		ptr[ptr_idx].value = 0xDEADF00D;
468b170d696SZhanjun Dong 		ptr[ptr_idx].flags = match->list[list_idx].flags;
469b170d696SZhanjun Dong 		ptr[ptr_idx].mask = match->list[list_idx].mask;
4709c8c7a7eSZhanjun Dong 	}
4719c8c7a7eSZhanjun Dong 
472b170d696SZhanjun Dong 	match = guc_capture_get_one_list(extlists, owner, type, capture_class);
473b170d696SZhanjun Dong 	if (match)
474b170d696SZhanjun Dong 		for (ptr_idx = list_num, list_idx = 0;
475b170d696SZhanjun Dong 		     ptr_idx < num_entries && list_idx < match->num_regs;
476b170d696SZhanjun Dong 		     ++ptr_idx, ++list_idx) {
477b170d696SZhanjun Dong 			ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
478b170d696SZhanjun Dong 			ptr[ptr_idx].value = 0xDEADF00D;
479b170d696SZhanjun Dong 			ptr[ptr_idx].flags = match->list[list_idx].flags;
480b170d696SZhanjun Dong 			ptr[ptr_idx].mask = match->list[list_idx].mask;
481b170d696SZhanjun Dong 		}
482b170d696SZhanjun Dong 
483b170d696SZhanjun Dong 	if (ptr_idx < num_entries)
484b170d696SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out-of %d.\n",
485b170d696SZhanjun Dong 			  ptr_idx, num_entries);
4869c8c7a7eSZhanjun Dong 
4879c8c7a7eSZhanjun Dong 	return 0;
4889c8c7a7eSZhanjun Dong }
4899c8c7a7eSZhanjun Dong 
4909c8c7a7eSZhanjun Dong static int
4919c8c7a7eSZhanjun Dong guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
4929c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class)
4939c8c7a7eSZhanjun Dong {
4949c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
495b170d696SZhanjun Dong 	int num_regs = 0;
4969c8c7a7eSZhanjun Dong 
4979c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class);
498b170d696SZhanjun Dong 	if (match)
499b170d696SZhanjun Dong 		num_regs = match->num_regs;
5009c8c7a7eSZhanjun Dong 
501b170d696SZhanjun Dong 	match = guc_capture_get_one_list(guc->capture->extlists, owner, type, capture_class);
502b170d696SZhanjun Dong 	if (match)
503b170d696SZhanjun Dong 		num_regs += match->num_regs;
504b170d696SZhanjun Dong 	else
505*8bfc4963SZhanjun Dong 		/*
506*8bfc4963SZhanjun Dong 		 * If a caller wants the full register dump size but we have
507*8bfc4963SZhanjun Dong 		 * not yet got the hw-config, which is before max_mmio_per_node
508*8bfc4963SZhanjun Dong 		 * is initialized, then provide a worst-case number for
509*8bfc4963SZhanjun Dong 		 * extlists based on max dss fuse bits, but only ever for
510*8bfc4963SZhanjun Dong 		 * render/compute
511*8bfc4963SZhanjun Dong 		 */
512*8bfc4963SZhanjun Dong 		if (owner == GUC_CAPTURE_LIST_INDEX_PF &&
513*8bfc4963SZhanjun Dong 		    type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
514*8bfc4963SZhanjun Dong 		    capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE &&
515*8bfc4963SZhanjun Dong 		    !guc->capture->max_mmio_per_node)
516b170d696SZhanjun Dong 			num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) *
517b170d696SZhanjun Dong 				    XE_MAX_DSS_FUSE_BITS;
518b170d696SZhanjun Dong 
519b170d696SZhanjun Dong 	return num_regs;
5209c8c7a7eSZhanjun Dong }
5219c8c7a7eSZhanjun Dong 
5229c8c7a7eSZhanjun Dong static int
5239c8c7a7eSZhanjun Dong guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
5249c8c7a7eSZhanjun Dong 			enum guc_capture_list_class_type capture_class,
5259c8c7a7eSZhanjun Dong 			size_t *size, bool is_purpose_est)
5269c8c7a7eSZhanjun Dong {
5279c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
5289c8c7a7eSZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
5299c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache;
5309c8c7a7eSZhanjun Dong 	int num_regs;
5319c8c7a7eSZhanjun Dong 
5329c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX);
5339c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX);
5349c8c7a7eSZhanjun Dong 
5359c8c7a7eSZhanjun Dong 	cache = &gc->ads_cache[owner][type][capture_class];
5369c8c7a7eSZhanjun Dong 	if (!gc->reglists) {
5379c8c7a7eSZhanjun Dong 		xe_gt_warn(gt, "No capture reglist for this device\n");
5389c8c7a7eSZhanjun Dong 		return -ENODEV;
5399c8c7a7eSZhanjun Dong 	}
5409c8c7a7eSZhanjun Dong 
5419c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
5429c8c7a7eSZhanjun Dong 		*size = cache->size;
5439c8c7a7eSZhanjun Dong 		return cache->status;
5449c8c7a7eSZhanjun Dong 	}
5459c8c7a7eSZhanjun Dong 
5469c8c7a7eSZhanjun Dong 	if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
5479c8c7a7eSZhanjun Dong 	    !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) {
5489c8c7a7eSZhanjun Dong 		if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL)
5499c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: global!\n");
5509c8c7a7eSZhanjun Dong 		else
5519c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n",
5529c8c7a7eSZhanjun Dong 				   capture_list_type_names[type], type,
5539c8c7a7eSZhanjun Dong 				   capture_engine_class_names[capture_class], capture_class);
5549c8c7a7eSZhanjun Dong 		return -ENODEV;
5559c8c7a7eSZhanjun Dong 	}
5569c8c7a7eSZhanjun Dong 
5579c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
5589c8c7a7eSZhanjun Dong 	/* intentional empty lists can exist depending on hw config */
5599c8c7a7eSZhanjun Dong 	if (!num_regs)
5609c8c7a7eSZhanjun Dong 		return -ENODATA;
5619c8c7a7eSZhanjun Dong 
5629c8c7a7eSZhanjun Dong 	if (size)
5639c8c7a7eSZhanjun Dong 		*size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
5649c8c7a7eSZhanjun Dong 				   (num_regs * sizeof(struct guc_mmio_reg)));
5659c8c7a7eSZhanjun Dong 
5669c8c7a7eSZhanjun Dong 	return 0;
5679c8c7a7eSZhanjun Dong }
5689c8c7a7eSZhanjun Dong 
5699c8c7a7eSZhanjun Dong /**
5709c8c7a7eSZhanjun Dong  * xe_guc_capture_getlistsize - Get list size for owner/type/class combination
5719c8c7a7eSZhanjun Dong  * @guc: The GuC object
5729c8c7a7eSZhanjun Dong  * @owner: PF/VF owner
5739c8c7a7eSZhanjun Dong  * @type: GuC capture register type
5749c8c7a7eSZhanjun Dong  * @capture_class: GuC capture engine class id
5759c8c7a7eSZhanjun Dong  * @size: Point to the size
5769c8c7a7eSZhanjun Dong  *
5779c8c7a7eSZhanjun Dong  * This function will get the list for the owner/type/class combination, and
5789c8c7a7eSZhanjun Dong  * return the page aligned list size.
5799c8c7a7eSZhanjun Dong  *
5809c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
5819c8c7a7eSZhanjun Dong  */
5829c8c7a7eSZhanjun Dong int
5839c8c7a7eSZhanjun Dong xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
5849c8c7a7eSZhanjun Dong 			   enum guc_capture_list_class_type capture_class, size_t *size)
5859c8c7a7eSZhanjun Dong {
5869c8c7a7eSZhanjun Dong 	return guc_capture_getlistsize(guc, owner, type, capture_class, size, false);
5879c8c7a7eSZhanjun Dong }
5889c8c7a7eSZhanjun Dong 
5899c8c7a7eSZhanjun Dong /**
5909c8c7a7eSZhanjun Dong  * xe_guc_capture_getlist - Get register capture list for owner/type/class
5919c8c7a7eSZhanjun Dong  * combination
5929c8c7a7eSZhanjun Dong  * @guc:	The GuC object
5939c8c7a7eSZhanjun Dong  * @owner:	PF/VF owner
5949c8c7a7eSZhanjun Dong  * @type:	GuC capture register type
5959c8c7a7eSZhanjun Dong  * @capture_class:	GuC capture engine class id
5969c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
5979c8c7a7eSZhanjun Dong  *
5989c8c7a7eSZhanjun Dong  * This function will get the register capture list for the owner/type/class
5999c8c7a7eSZhanjun Dong  * combination.
6009c8c7a7eSZhanjun Dong  *
6019c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
6029c8c7a7eSZhanjun Dong  */
6039c8c7a7eSZhanjun Dong int
6049c8c7a7eSZhanjun Dong xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type,
6059c8c7a7eSZhanjun Dong 		       enum guc_capture_list_class_type capture_class, void **outptr)
6069c8c7a7eSZhanjun Dong {
6079c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
6089c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class];
6099c8c7a7eSZhanjun Dong 	struct guc_debug_capture_list *listnode;
6109c8c7a7eSZhanjun Dong 	int ret, num_regs;
6119c8c7a7eSZhanjun Dong 	u8 *caplist, *tmp;
6129c8c7a7eSZhanjun Dong 	size_t size = 0;
6139c8c7a7eSZhanjun Dong 
6149c8c7a7eSZhanjun Dong 	if (!gc->reglists)
6159c8c7a7eSZhanjun Dong 		return -ENODEV;
6169c8c7a7eSZhanjun Dong 
6179c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
6189c8c7a7eSZhanjun Dong 		*outptr = cache->ptr;
6199c8c7a7eSZhanjun Dong 		return cache->status;
6209c8c7a7eSZhanjun Dong 	}
6219c8c7a7eSZhanjun Dong 
6229c8c7a7eSZhanjun Dong 	ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size);
6239c8c7a7eSZhanjun Dong 	if (ret) {
6249c8c7a7eSZhanjun Dong 		cache->is_valid = true;
6259c8c7a7eSZhanjun Dong 		cache->ptr = NULL;
6269c8c7a7eSZhanjun Dong 		cache->size = 0;
6279c8c7a7eSZhanjun Dong 		cache->status = ret;
6289c8c7a7eSZhanjun Dong 		return ret;
6299c8c7a7eSZhanjun Dong 	}
6309c8c7a7eSZhanjun Dong 
6319c8c7a7eSZhanjun Dong 	caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL);
6329c8c7a7eSZhanjun Dong 	if (!caplist)
6339c8c7a7eSZhanjun Dong 		return -ENOMEM;
6349c8c7a7eSZhanjun Dong 
6359c8c7a7eSZhanjun Dong 	/* populate capture list header */
6369c8c7a7eSZhanjun Dong 	tmp = caplist;
6379c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
6389c8c7a7eSZhanjun Dong 	listnode = (struct guc_debug_capture_list *)tmp;
6399c8c7a7eSZhanjun Dong 	listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
6409c8c7a7eSZhanjun Dong 
6419c8c7a7eSZhanjun Dong 	/* populate list of register descriptor */
6429c8c7a7eSZhanjun Dong 	tmp += sizeof(struct guc_debug_capture_list);
6439c8c7a7eSZhanjun Dong 	guc_capture_list_init(guc, owner, type, capture_class,
6449c8c7a7eSZhanjun Dong 			      (struct guc_mmio_reg *)tmp, num_regs);
6459c8c7a7eSZhanjun Dong 
6469c8c7a7eSZhanjun Dong 	/* cache this list */
6479c8c7a7eSZhanjun Dong 	cache->is_valid = true;
6489c8c7a7eSZhanjun Dong 	cache->ptr = caplist;
6499c8c7a7eSZhanjun Dong 	cache->size = size;
6509c8c7a7eSZhanjun Dong 	cache->status = 0;
6519c8c7a7eSZhanjun Dong 
6529c8c7a7eSZhanjun Dong 	*outptr = caplist;
6539c8c7a7eSZhanjun Dong 
6549c8c7a7eSZhanjun Dong 	return 0;
6559c8c7a7eSZhanjun Dong }
6569c8c7a7eSZhanjun Dong 
6579c8c7a7eSZhanjun Dong /**
6589c8c7a7eSZhanjun Dong  * xe_guc_capture_getnullheader - Get a null list for register capture
6599c8c7a7eSZhanjun Dong  * @guc:	The GuC object
6609c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
6619c8c7a7eSZhanjun Dong  * @size:	Point to the size
6629c8c7a7eSZhanjun Dong  *
6639c8c7a7eSZhanjun Dong  * This function will alloc for a null list for register capture.
6649c8c7a7eSZhanjun Dong  *
6659c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
6669c8c7a7eSZhanjun Dong  */
6679c8c7a7eSZhanjun Dong int
6689c8c7a7eSZhanjun Dong xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size)
6699c8c7a7eSZhanjun Dong {
6709c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
6719c8c7a7eSZhanjun Dong 	int tmp = sizeof(u32) * 4;
6729c8c7a7eSZhanjun Dong 	void *null_header;
6739c8c7a7eSZhanjun Dong 
6749c8c7a7eSZhanjun Dong 	if (gc->ads_null_cache) {
6759c8c7a7eSZhanjun Dong 		*outptr = gc->ads_null_cache;
6769c8c7a7eSZhanjun Dong 		*size = tmp;
6779c8c7a7eSZhanjun Dong 		return 0;
6789c8c7a7eSZhanjun Dong 	}
6799c8c7a7eSZhanjun Dong 
6809c8c7a7eSZhanjun Dong 	null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL);
6819c8c7a7eSZhanjun Dong 	if (!null_header)
6829c8c7a7eSZhanjun Dong 		return -ENOMEM;
6839c8c7a7eSZhanjun Dong 
6849c8c7a7eSZhanjun Dong 	gc->ads_null_cache = null_header;
6859c8c7a7eSZhanjun Dong 	*outptr = null_header;
6869c8c7a7eSZhanjun Dong 	*size = tmp;
6879c8c7a7eSZhanjun Dong 
6889c8c7a7eSZhanjun Dong 	return 0;
6899c8c7a7eSZhanjun Dong }
6909c8c7a7eSZhanjun Dong 
6919c8c7a7eSZhanjun Dong /**
6929c8c7a7eSZhanjun Dong  * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture
6939c8c7a7eSZhanjun Dong  * @guc: point to xe_guc structure
6949c8c7a7eSZhanjun Dong  *
6959c8c7a7eSZhanjun Dong  * Calculate the worst size for GuC register capture by including all possible engines classes.
6969c8c7a7eSZhanjun Dong  *
6979c8c7a7eSZhanjun Dong  * Returns: Calculated size
6989c8c7a7eSZhanjun Dong  */
6999c8c7a7eSZhanjun Dong size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
7009c8c7a7eSZhanjun Dong {
7019c8c7a7eSZhanjun Dong 	size_t total_size, class_size, instance_size, global_size;
7029c8c7a7eSZhanjun Dong 	int i, j;
7039c8c7a7eSZhanjun Dong 
7049c8c7a7eSZhanjun Dong 	/*
7059c8c7a7eSZhanjun Dong 	 * This function calculates the worst case register lists size by
7069c8c7a7eSZhanjun Dong 	 * including all possible engines classes. It is called during the
7079c8c7a7eSZhanjun Dong 	 * first of a two-phase GuC (and ADS-population) initialization
7089c8c7a7eSZhanjun Dong 	 * sequence, that is, during the pre-hwconfig phase before we have
7099c8c7a7eSZhanjun Dong 	 * the exact engine fusing info.
7109c8c7a7eSZhanjun Dong 	 */
7119c8c7a7eSZhanjun Dong 	total_size = PAGE_SIZE;	/* Pad a page in front for empty lists */
7129c8c7a7eSZhanjun Dong 	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
7139c8c7a7eSZhanjun Dong 		for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) {
7149c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
7159c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
7169c8c7a7eSZhanjun Dong 						       j, &class_size) < 0)
7179c8c7a7eSZhanjun Dong 				class_size = 0;
7189c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
7199c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
7209c8c7a7eSZhanjun Dong 						       j, &instance_size) < 0)
7219c8c7a7eSZhanjun Dong 				instance_size = 0;
7229c8c7a7eSZhanjun Dong 			total_size += class_size + instance_size;
7239c8c7a7eSZhanjun Dong 		}
7249c8c7a7eSZhanjun Dong 		if (xe_guc_capture_getlistsize(guc, i,
7259c8c7a7eSZhanjun Dong 					       GUC_STATE_CAPTURE_TYPE_GLOBAL,
7269c8c7a7eSZhanjun Dong 					       0, &global_size) < 0)
7279c8c7a7eSZhanjun Dong 			global_size = 0;
7289c8c7a7eSZhanjun Dong 		total_size += global_size;
7299c8c7a7eSZhanjun Dong 	}
7309c8c7a7eSZhanjun Dong 
7319c8c7a7eSZhanjun Dong 	return PAGE_ALIGN(total_size);
7329c8c7a7eSZhanjun Dong }
7339c8c7a7eSZhanjun Dong 
73484d15f42SZhanjun Dong static int guc_capture_output_size_est(struct xe_guc *guc)
73584d15f42SZhanjun Dong {
73684d15f42SZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
73784d15f42SZhanjun Dong 	struct xe_hw_engine *hwe;
73884d15f42SZhanjun Dong 	enum xe_hw_engine_id id;
73984d15f42SZhanjun Dong 
74084d15f42SZhanjun Dong 	int capture_size = 0;
74184d15f42SZhanjun Dong 	size_t tmp = 0;
74284d15f42SZhanjun Dong 
74384d15f42SZhanjun Dong 	if (!guc->capture)
74484d15f42SZhanjun Dong 		return -ENODEV;
74584d15f42SZhanjun Dong 
74684d15f42SZhanjun Dong 	/*
74784d15f42SZhanjun Dong 	 * If every single engine-instance suffered a failure in quick succession but
74884d15f42SZhanjun Dong 	 * were all unrelated, then a burst of multiple error-capture events would dump
74984d15f42SZhanjun Dong 	 * registers for every one engine instance, one at a time. In this case, GuC
75084d15f42SZhanjun Dong 	 * would even dump the global-registers repeatedly.
75184d15f42SZhanjun Dong 	 *
75284d15f42SZhanjun Dong 	 * For each engine instance, there would be 1 x guc_state_capture_group_t output
75384d15f42SZhanjun Dong 	 * followed by 3 x guc_state_capture_t lists. The latter is how the register
75484d15f42SZhanjun Dong 	 * dumps are split across different register types (where the '3' are global vs class
75584d15f42SZhanjun Dong 	 * vs instance).
75684d15f42SZhanjun Dong 	 */
75784d15f42SZhanjun Dong 	for_each_hw_engine(hwe, gt, id) {
75884d15f42SZhanjun Dong 		enum guc_capture_list_class_type capture_class;
75984d15f42SZhanjun Dong 
76084d15f42SZhanjun Dong 		capture_class = xe_engine_class_to_guc_capture_class(hwe->class);
76184d15f42SZhanjun Dong 		capture_size += sizeof(struct guc_state_capture_group_header_t) +
76284d15f42SZhanjun Dong 					 (3 * sizeof(struct guc_state_capture_header_t));
76384d15f42SZhanjun Dong 
76484d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_GLOBAL,
76584d15f42SZhanjun Dong 					     0, &tmp, true))
76684d15f42SZhanjun Dong 			capture_size += tmp;
76784d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
76884d15f42SZhanjun Dong 					     capture_class, &tmp, true))
76984d15f42SZhanjun Dong 			capture_size += tmp;
77084d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
77184d15f42SZhanjun Dong 					     capture_class, &tmp, true))
77284d15f42SZhanjun Dong 			capture_size += tmp;
77384d15f42SZhanjun Dong 	}
77484d15f42SZhanjun Dong 
77584d15f42SZhanjun Dong 	return capture_size;
77684d15f42SZhanjun Dong }
77784d15f42SZhanjun Dong 
77884d15f42SZhanjun Dong /*
77984d15f42SZhanjun Dong  * Add on a 3x multiplier to allow for multiple back-to-back captures occurring
78084d15f42SZhanjun Dong  * before the Xe can read the data out and process it
78184d15f42SZhanjun Dong  */
78284d15f42SZhanjun Dong #define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
78384d15f42SZhanjun Dong 
78484d15f42SZhanjun Dong static void check_guc_capture_size(struct xe_guc *guc)
78584d15f42SZhanjun Dong {
78684d15f42SZhanjun Dong 	int capture_size = guc_capture_output_size_est(guc);
78784d15f42SZhanjun Dong 	int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
78884d15f42SZhanjun Dong 	u32 buffer_size = xe_guc_log_section_size_capture(&guc->log);
78984d15f42SZhanjun Dong 
79084d15f42SZhanjun Dong 	/*
79184d15f42SZhanjun Dong 	 * NOTE: capture_size is much smaller than the capture region
79284d15f42SZhanjun Dong 	 * allocation (DG2: <80K vs 1MB).
79384d15f42SZhanjun Dong 	 * Additionally, its based on space needed to fit all engines getting
79484d15f42SZhanjun Dong 	 * reset at once within the same G2H handler task slot. This is very
79584d15f42SZhanjun Dong 	 * unlikely. However, if GuC really does run out of space for whatever
79684d15f42SZhanjun Dong 	 * reason, we will see an separate warning message when processing the
79784d15f42SZhanjun Dong 	 * G2H event capture-notification, search for:
79884d15f42SZhanjun Dong 	 * xe_guc_STATE_CAPTURE_EVENT_STATUS_NOSPACE.
79984d15f42SZhanjun Dong 	 */
80084d15f42SZhanjun Dong 	if (capture_size < 0)
80184d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc),
80284d15f42SZhanjun Dong 			  "Failed to calculate error state capture buffer minimum size: %d!\n",
80384d15f42SZhanjun Dong 			  capture_size);
80484d15f42SZhanjun Dong 	if (capture_size > buffer_size)
80584d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc), "Error state capture buffer maybe small: %d < %d\n",
80684d15f42SZhanjun Dong 			  buffer_size, capture_size);
80784d15f42SZhanjun Dong 	else if (spare_size > buffer_size)
80884d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc),
80984d15f42SZhanjun Dong 			  "Error state capture buffer lacks spare size: %d < %d (min = %d)\n",
81084d15f42SZhanjun Dong 			  buffer_size, spare_size, capture_size);
81184d15f42SZhanjun Dong }
81284d15f42SZhanjun Dong 
813*8bfc4963SZhanjun Dong static void
814*8bfc4963SZhanjun Dong guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node,
815*8bfc4963SZhanjun Dong 			     struct list_head *list)
816*8bfc4963SZhanjun Dong {
817*8bfc4963SZhanjun Dong 	list_add_tail(&node->link, list);
818*8bfc4963SZhanjun Dong }
819*8bfc4963SZhanjun Dong 
820*8bfc4963SZhanjun Dong static void
821*8bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(struct xe_guc_state_capture *gc,
822*8bfc4963SZhanjun Dong 				struct __guc_capture_parsed_output *node)
823*8bfc4963SZhanjun Dong {
824*8bfc4963SZhanjun Dong 	guc_capture_add_node_to_list(node, &gc->outlist);
825*8bfc4963SZhanjun Dong }
826*8bfc4963SZhanjun Dong 
827*8bfc4963SZhanjun Dong static void
828*8bfc4963SZhanjun Dong guc_capture_add_node_to_cachelist(struct xe_guc_state_capture *gc,
829*8bfc4963SZhanjun Dong 				  struct __guc_capture_parsed_output *node)
830*8bfc4963SZhanjun Dong {
831*8bfc4963SZhanjun Dong 	guc_capture_add_node_to_list(node, &gc->cachelist);
832*8bfc4963SZhanjun Dong }
833*8bfc4963SZhanjun Dong 
834*8bfc4963SZhanjun Dong static void
835*8bfc4963SZhanjun Dong guc_capture_init_node(struct xe_guc *guc, struct __guc_capture_parsed_output *node)
836*8bfc4963SZhanjun Dong {
837*8bfc4963SZhanjun Dong 	struct guc_mmio_reg *tmp[GUC_STATE_CAPTURE_TYPE_MAX];
838*8bfc4963SZhanjun Dong 	int i;
839*8bfc4963SZhanjun Dong 
840*8bfc4963SZhanjun Dong 	for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
841*8bfc4963SZhanjun Dong 		tmp[i] = node->reginfo[i].regs;
842*8bfc4963SZhanjun Dong 		memset(tmp[i], 0, sizeof(struct guc_mmio_reg) *
843*8bfc4963SZhanjun Dong 		       guc->capture->max_mmio_per_node);
844*8bfc4963SZhanjun Dong 	}
845*8bfc4963SZhanjun Dong 	memset(node, 0, sizeof(*node));
846*8bfc4963SZhanjun Dong 	for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i)
847*8bfc4963SZhanjun Dong 		node->reginfo[i].regs = tmp[i];
848*8bfc4963SZhanjun Dong 
849*8bfc4963SZhanjun Dong 	INIT_LIST_HEAD(&node->link);
850*8bfc4963SZhanjun Dong }
851*8bfc4963SZhanjun Dong 
852*8bfc4963SZhanjun Dong /**
853*8bfc4963SZhanjun Dong  * DOC: Init, G2H-event and reporting flows for GuC-error-capture
854*8bfc4963SZhanjun Dong  *
855*8bfc4963SZhanjun Dong  * KMD Init time flows:
856*8bfc4963SZhanjun Dong  * --------------------
857*8bfc4963SZhanjun Dong  *     --> alloc A: GuC input capture regs lists (registered to GuC via ADS).
858*8bfc4963SZhanjun Dong  *                  xe_guc_ads acquires the register lists by calling
859*8bfc4963SZhanjun Dong  *                  xe_guc_capture_getlistsize and xe_guc_capture_getlist 'n' times,
860*8bfc4963SZhanjun Dong  *                  where n = 1 for global-reg-list +
861*8bfc4963SZhanjun Dong  *                            num_engine_classes for class-reg-list +
862*8bfc4963SZhanjun Dong  *                            num_engine_classes for instance-reg-list
863*8bfc4963SZhanjun Dong  *                               (since all instances of the same engine-class type
864*8bfc4963SZhanjun Dong  *                                have an identical engine-instance register-list).
865*8bfc4963SZhanjun Dong  *                  ADS module also calls separately for PF vs VF.
866*8bfc4963SZhanjun Dong  *
867*8bfc4963SZhanjun Dong  *     --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))
868*8bfc4963SZhanjun Dong  *                  Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small)
869*8bfc4963SZhanjun Dong  *                  Note2: 'x 3' to hold multiple capture groups
870*8bfc4963SZhanjun Dong  *
871*8bfc4963SZhanjun Dong  * GUC Runtime notify capture:
872*8bfc4963SZhanjun Dong  * --------------------------
873*8bfc4963SZhanjun Dong  *     --> G2H STATE_CAPTURE_NOTIFICATION
874*8bfc4963SZhanjun Dong  *                   L--> xe_guc_capture_process
875*8bfc4963SZhanjun Dong  *                           L--> Loop through B (head..tail) and for each engine instance's
876*8bfc4963SZhanjun Dong  *                                err-state-captured register-list we find, we alloc 'C':
877*8bfc4963SZhanjun Dong  *      --> alloc C: A capture-output-node structure that includes misc capture info along
878*8bfc4963SZhanjun Dong  *                   with 3 register list dumps (global, engine-class and engine-instance)
879*8bfc4963SZhanjun Dong  *                   This node is created from a pre-allocated list of blank nodes in
880*8bfc4963SZhanjun Dong  *                   guc->capture->cachelist and populated with the error-capture
881*8bfc4963SZhanjun Dong  *                   data from GuC and then it's added into guc->capture->outlist linked
882*8bfc4963SZhanjun Dong  *                   list. This list is used for matchup and printout by xe_devcoredump_read
883*8bfc4963SZhanjun Dong  *                   and xe_hw_engine_snapshot_print, (when user invokes the devcoredump sysfs).
884*8bfc4963SZhanjun Dong  *
885*8bfc4963SZhanjun Dong  * GUC --> notify context reset:
886*8bfc4963SZhanjun Dong  * -----------------------------
887*8bfc4963SZhanjun Dong  *     --> guc_exec_queue_timedout_job
888*8bfc4963SZhanjun Dong  *                   L--> xe_devcoredump
889*8bfc4963SZhanjun Dong  *                          L--> devcoredump_snapshot
890*8bfc4963SZhanjun Dong  *                               --> xe_hw_engine_snapshot_capture
891*8bfc4963SZhanjun Dong  *
892*8bfc4963SZhanjun Dong  * User Sysfs / Debugfs
893*8bfc4963SZhanjun Dong  * --------------------
894*8bfc4963SZhanjun Dong  *      --> xe_devcoredump_read->
895*8bfc4963SZhanjun Dong  *             L--> xxx_snapshot_print
896*8bfc4963SZhanjun Dong  *                    L--> xe_hw_engine_snapshot_print
897*8bfc4963SZhanjun Dong  *                         Print register lists values saved at
898*8bfc4963SZhanjun Dong  *                         guc->capture->outlist
899*8bfc4963SZhanjun Dong  *
900*8bfc4963SZhanjun Dong  */
901*8bfc4963SZhanjun Dong 
902*8bfc4963SZhanjun Dong static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
903*8bfc4963SZhanjun Dong {
904*8bfc4963SZhanjun Dong 	if (buf->wr >= buf->rd)
905*8bfc4963SZhanjun Dong 		return (buf->wr - buf->rd);
906*8bfc4963SZhanjun Dong 	return (buf->size - buf->rd) + buf->wr;
907*8bfc4963SZhanjun Dong }
908*8bfc4963SZhanjun Dong 
909*8bfc4963SZhanjun Dong static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
910*8bfc4963SZhanjun Dong {
911*8bfc4963SZhanjun Dong 	if (buf->rd > buf->wr)
912*8bfc4963SZhanjun Dong 		return (buf->size - buf->rd);
913*8bfc4963SZhanjun Dong 	return (buf->wr - buf->rd);
914*8bfc4963SZhanjun Dong }
915*8bfc4963SZhanjun Dong 
916*8bfc4963SZhanjun Dong /*
917*8bfc4963SZhanjun Dong  * GuC's error-capture output is a ring buffer populated in a byte-stream fashion:
918*8bfc4963SZhanjun Dong  *
919*8bfc4963SZhanjun Dong  * The GuC Log buffer region for error-capture is managed like a ring buffer.
920*8bfc4963SZhanjun Dong  * The GuC firmware dumps error capture logs into this ring in a byte-stream flow.
921*8bfc4963SZhanjun Dong  * Additionally, as per the current and foreseeable future, all packed error-
922*8bfc4963SZhanjun Dong  * capture output structures are dword aligned.
923*8bfc4963SZhanjun Dong  *
924*8bfc4963SZhanjun Dong  * That said, if the GuC firmware is in the midst of writing a structure that is larger
925*8bfc4963SZhanjun Dong  * than one dword but the tail end of the err-capture buffer-region has lesser space left,
926*8bfc4963SZhanjun Dong  * we would need to extract that structure one dword at a time straddled across the end,
927*8bfc4963SZhanjun Dong  * onto the start of the ring.
928*8bfc4963SZhanjun Dong  *
929*8bfc4963SZhanjun Dong  * Below function, guc_capture_log_remove_bytes is a helper for that. All callers of this
930*8bfc4963SZhanjun Dong  * function would typically do a straight-up memcpy from the ring contents and will only
931*8bfc4963SZhanjun Dong  * call this helper if their structure-extraction is straddling across the end of the
932*8bfc4963SZhanjun Dong  * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease
933*8bfc4963SZhanjun Dong  * scalability for future expansion of output data types without requiring a redesign
934*8bfc4963SZhanjun Dong  * of the flow controls.
935*8bfc4963SZhanjun Dong  */
936*8bfc4963SZhanjun Dong static int
937*8bfc4963SZhanjun Dong guc_capture_log_remove_bytes(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
938*8bfc4963SZhanjun Dong 			     void *out, int bytes_needed)
939*8bfc4963SZhanjun Dong {
940*8bfc4963SZhanjun Dong #define GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX	3
941*8bfc4963SZhanjun Dong 
942*8bfc4963SZhanjun Dong 	int fill_size = 0, tries = GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX;
943*8bfc4963SZhanjun Dong 	int copy_size, avail;
944*8bfc4963SZhanjun Dong 
945*8bfc4963SZhanjun Dong 	xe_assert(guc_to_xe(guc), bytes_needed % sizeof(u32) == 0);
946*8bfc4963SZhanjun Dong 
947*8bfc4963SZhanjun Dong 	if (bytes_needed > guc_capture_buf_cnt(buf))
948*8bfc4963SZhanjun Dong 		return -1;
949*8bfc4963SZhanjun Dong 
950*8bfc4963SZhanjun Dong 	while (bytes_needed > 0 && tries--) {
951*8bfc4963SZhanjun Dong 		int misaligned;
952*8bfc4963SZhanjun Dong 
953*8bfc4963SZhanjun Dong 		avail = guc_capture_buf_cnt_to_end(buf);
954*8bfc4963SZhanjun Dong 		misaligned = avail % sizeof(u32);
955*8bfc4963SZhanjun Dong 		/* wrap if at end */
956*8bfc4963SZhanjun Dong 		if (!avail) {
957*8bfc4963SZhanjun Dong 			/* output stream clipped */
958*8bfc4963SZhanjun Dong 			if (!buf->rd)
959*8bfc4963SZhanjun Dong 				return fill_size;
960*8bfc4963SZhanjun Dong 			buf->rd = 0;
961*8bfc4963SZhanjun Dong 			continue;
962*8bfc4963SZhanjun Dong 		}
963*8bfc4963SZhanjun Dong 
964*8bfc4963SZhanjun Dong 		/* Only copy to u32 aligned data */
965*8bfc4963SZhanjun Dong 		copy_size = avail < bytes_needed ? avail - misaligned : bytes_needed;
966*8bfc4963SZhanjun Dong 		xe_map_memcpy_from(guc_to_xe(guc), out + fill_size, &guc->log.bo->vmap,
967*8bfc4963SZhanjun Dong 				   buf->data_offset + buf->rd, copy_size);
968*8bfc4963SZhanjun Dong 		buf->rd += copy_size;
969*8bfc4963SZhanjun Dong 		fill_size += copy_size;
970*8bfc4963SZhanjun Dong 		bytes_needed -= copy_size;
971*8bfc4963SZhanjun Dong 
972*8bfc4963SZhanjun Dong 		if (misaligned)
973*8bfc4963SZhanjun Dong 			xe_gt_warn(guc_to_gt(guc),
974*8bfc4963SZhanjun Dong 				   "Bytes extraction not dword aligned, clipping.\n");
975*8bfc4963SZhanjun Dong 	}
976*8bfc4963SZhanjun Dong 
977*8bfc4963SZhanjun Dong 	return fill_size;
978*8bfc4963SZhanjun Dong }
979*8bfc4963SZhanjun Dong 
980*8bfc4963SZhanjun Dong static int
981*8bfc4963SZhanjun Dong guc_capture_log_get_group_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
982*8bfc4963SZhanjun Dong 			      struct guc_state_capture_group_header_t *ghdr)
983*8bfc4963SZhanjun Dong {
984*8bfc4963SZhanjun Dong 	int fullsize = sizeof(struct guc_state_capture_group_header_t);
985*8bfc4963SZhanjun Dong 
986*8bfc4963SZhanjun Dong 	if (guc_capture_log_remove_bytes(guc, buf, ghdr, fullsize) != fullsize)
987*8bfc4963SZhanjun Dong 		return -1;
988*8bfc4963SZhanjun Dong 	return 0;
989*8bfc4963SZhanjun Dong }
990*8bfc4963SZhanjun Dong 
991*8bfc4963SZhanjun Dong static int
992*8bfc4963SZhanjun Dong guc_capture_log_get_data_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
993*8bfc4963SZhanjun Dong 			     struct guc_state_capture_header_t *hdr)
994*8bfc4963SZhanjun Dong {
995*8bfc4963SZhanjun Dong 	int fullsize = sizeof(struct guc_state_capture_header_t);
996*8bfc4963SZhanjun Dong 
997*8bfc4963SZhanjun Dong 	if (guc_capture_log_remove_bytes(guc, buf, hdr, fullsize) != fullsize)
998*8bfc4963SZhanjun Dong 		return -1;
999*8bfc4963SZhanjun Dong 	return 0;
1000*8bfc4963SZhanjun Dong }
1001*8bfc4963SZhanjun Dong 
1002*8bfc4963SZhanjun Dong static int
1003*8bfc4963SZhanjun Dong guc_capture_log_get_register(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
1004*8bfc4963SZhanjun Dong 			     struct guc_mmio_reg *reg)
1005*8bfc4963SZhanjun Dong {
1006*8bfc4963SZhanjun Dong 	int fullsize = sizeof(struct guc_mmio_reg);
1007*8bfc4963SZhanjun Dong 
1008*8bfc4963SZhanjun Dong 	if (guc_capture_log_remove_bytes(guc, buf, reg, fullsize) != fullsize)
1009*8bfc4963SZhanjun Dong 		return -1;
1010*8bfc4963SZhanjun Dong 	return 0;
1011*8bfc4963SZhanjun Dong }
1012*8bfc4963SZhanjun Dong 
1013*8bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
1014*8bfc4963SZhanjun Dong guc_capture_get_prealloc_node(struct xe_guc *guc)
1015*8bfc4963SZhanjun Dong {
1016*8bfc4963SZhanjun Dong 	struct __guc_capture_parsed_output *found = NULL;
1017*8bfc4963SZhanjun Dong 
1018*8bfc4963SZhanjun Dong 	if (!list_empty(&guc->capture->cachelist)) {
1019*8bfc4963SZhanjun Dong 		struct __guc_capture_parsed_output *n, *ntmp;
1020*8bfc4963SZhanjun Dong 
1021*8bfc4963SZhanjun Dong 		/* get first avail node from the cache list */
1022*8bfc4963SZhanjun Dong 		list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) {
1023*8bfc4963SZhanjun Dong 			found = n;
1024*8bfc4963SZhanjun Dong 			break;
1025*8bfc4963SZhanjun Dong 		}
1026*8bfc4963SZhanjun Dong 	} else {
1027*8bfc4963SZhanjun Dong 		struct __guc_capture_parsed_output *n, *ntmp;
1028*8bfc4963SZhanjun Dong 
1029*8bfc4963SZhanjun Dong 		/* traverse down and steal back the oldest node already allocated */
1030*8bfc4963SZhanjun Dong 		list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) {
1031*8bfc4963SZhanjun Dong 			found = n;
1032*8bfc4963SZhanjun Dong 		}
1033*8bfc4963SZhanjun Dong 	}
1034*8bfc4963SZhanjun Dong 	if (found) {
1035*8bfc4963SZhanjun Dong 		list_del(&found->link);
1036*8bfc4963SZhanjun Dong 		guc_capture_init_node(guc, found);
1037*8bfc4963SZhanjun Dong 	}
1038*8bfc4963SZhanjun Dong 
1039*8bfc4963SZhanjun Dong 	return found;
1040*8bfc4963SZhanjun Dong }
1041*8bfc4963SZhanjun Dong 
1042*8bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
1043*8bfc4963SZhanjun Dong guc_capture_clone_node(struct xe_guc *guc, struct __guc_capture_parsed_output *original,
1044*8bfc4963SZhanjun Dong 		       u32 keep_reglist_mask)
1045*8bfc4963SZhanjun Dong {
1046*8bfc4963SZhanjun Dong 	struct __guc_capture_parsed_output *new;
1047*8bfc4963SZhanjun Dong 	int i;
1048*8bfc4963SZhanjun Dong 
1049*8bfc4963SZhanjun Dong 	new = guc_capture_get_prealloc_node(guc);
1050*8bfc4963SZhanjun Dong 	if (!new)
1051*8bfc4963SZhanjun Dong 		return NULL;
1052*8bfc4963SZhanjun Dong 	if (!original)
1053*8bfc4963SZhanjun Dong 		return new;
1054*8bfc4963SZhanjun Dong 
1055*8bfc4963SZhanjun Dong 	new->is_partial = original->is_partial;
1056*8bfc4963SZhanjun Dong 
1057*8bfc4963SZhanjun Dong 	/* copy reg-lists that we want to clone */
1058*8bfc4963SZhanjun Dong 	for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1059*8bfc4963SZhanjun Dong 		if (keep_reglist_mask & BIT(i)) {
1060*8bfc4963SZhanjun Dong 			XE_WARN_ON(original->reginfo[i].num_regs  >
1061*8bfc4963SZhanjun Dong 				   guc->capture->max_mmio_per_node);
1062*8bfc4963SZhanjun Dong 
1063*8bfc4963SZhanjun Dong 			memcpy(new->reginfo[i].regs, original->reginfo[i].regs,
1064*8bfc4963SZhanjun Dong 			       original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg));
1065*8bfc4963SZhanjun Dong 
1066*8bfc4963SZhanjun Dong 			new->reginfo[i].num_regs = original->reginfo[i].num_regs;
1067*8bfc4963SZhanjun Dong 			new->reginfo[i].vfid  = original->reginfo[i].vfid;
1068*8bfc4963SZhanjun Dong 
1069*8bfc4963SZhanjun Dong 			if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) {
1070*8bfc4963SZhanjun Dong 				new->eng_class = original->eng_class;
1071*8bfc4963SZhanjun Dong 			} else if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
1072*8bfc4963SZhanjun Dong 				new->eng_inst = original->eng_inst;
1073*8bfc4963SZhanjun Dong 				new->guc_id = original->guc_id;
1074*8bfc4963SZhanjun Dong 				new->lrca = original->lrca;
1075*8bfc4963SZhanjun Dong 			}
1076*8bfc4963SZhanjun Dong 		}
1077*8bfc4963SZhanjun Dong 	}
1078*8bfc4963SZhanjun Dong 
1079*8bfc4963SZhanjun Dong 	return new;
1080*8bfc4963SZhanjun Dong }
1081*8bfc4963SZhanjun Dong 
1082*8bfc4963SZhanjun Dong static int
1083*8bfc4963SZhanjun Dong guc_capture_extract_reglists(struct xe_guc *guc, struct __guc_capture_bufstate *buf)
1084*8bfc4963SZhanjun Dong {
1085*8bfc4963SZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
1086*8bfc4963SZhanjun Dong 	struct guc_state_capture_group_header_t ghdr = {0};
1087*8bfc4963SZhanjun Dong 	struct guc_state_capture_header_t hdr = {0};
1088*8bfc4963SZhanjun Dong 	struct __guc_capture_parsed_output *node = NULL;
1089*8bfc4963SZhanjun Dong 	struct guc_mmio_reg *regs = NULL;
1090*8bfc4963SZhanjun Dong 	int i, numlists, numregs, ret = 0;
1091*8bfc4963SZhanjun Dong 	enum guc_state_capture_type datatype;
1092*8bfc4963SZhanjun Dong 	struct guc_mmio_reg tmp;
1093*8bfc4963SZhanjun Dong 	bool is_partial = false;
1094*8bfc4963SZhanjun Dong 
1095*8bfc4963SZhanjun Dong 	i = guc_capture_buf_cnt(buf);
1096*8bfc4963SZhanjun Dong 	if (!i)
1097*8bfc4963SZhanjun Dong 		return -ENODATA;
1098*8bfc4963SZhanjun Dong 
1099*8bfc4963SZhanjun Dong 	if (i % sizeof(u32)) {
1100*8bfc4963SZhanjun Dong 		xe_gt_warn(gt, "Got mis-aligned register capture entries\n");
1101*8bfc4963SZhanjun Dong 		ret = -EIO;
1102*8bfc4963SZhanjun Dong 		goto bailout;
1103*8bfc4963SZhanjun Dong 	}
1104*8bfc4963SZhanjun Dong 
1105*8bfc4963SZhanjun Dong 	/* first get the capture group header */
1106*8bfc4963SZhanjun Dong 	if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {
1107*8bfc4963SZhanjun Dong 		ret = -EIO;
1108*8bfc4963SZhanjun Dong 		goto bailout;
1109*8bfc4963SZhanjun Dong 	}
1110*8bfc4963SZhanjun Dong 	/*
1111*8bfc4963SZhanjun Dong 	 * we would typically expect a layout as below where n would be expected to be
1112*8bfc4963SZhanjun Dong 	 * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine
1113*8bfc4963SZhanjun Dong 	 * instances being reset together.
1114*8bfc4963SZhanjun Dong 	 * ____________________________________________
1115*8bfc4963SZhanjun Dong 	 * | Capture Group                            |
1116*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1117*8bfc4963SZhanjun Dong 	 * | | Capture Group Header:                | |
1118*8bfc4963SZhanjun Dong 	 * | |  - num_captures = 5                  | |
1119*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1120*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1121*8bfc4963SZhanjun Dong 	 * | | Capture1:                            | |
1122*8bfc4963SZhanjun Dong 	 * | |  Hdr: GLOBAL, numregs=a              | |
1123*8bfc4963SZhanjun Dong 	 * | | ____________________________________ | |
1124*8bfc4963SZhanjun Dong 	 * | | | Reglist                          | | |
1125*8bfc4963SZhanjun Dong 	 * | | | - reg1, reg2, ... rega           | | |
1126*8bfc4963SZhanjun Dong 	 * | | |__________________________________| | |
1127*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1128*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1129*8bfc4963SZhanjun Dong 	 * | | Capture2:                            | |
1130*8bfc4963SZhanjun Dong 	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=b| |
1131*8bfc4963SZhanjun Dong 	 * | | ____________________________________ | |
1132*8bfc4963SZhanjun Dong 	 * | | | Reglist                          | | |
1133*8bfc4963SZhanjun Dong 	 * | | | - reg1, reg2, ... regb           | | |
1134*8bfc4963SZhanjun Dong 	 * | | |__________________________________| | |
1135*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1136*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1137*8bfc4963SZhanjun Dong 	 * | | Capture3:                            | |
1138*8bfc4963SZhanjun Dong 	 * | |  Hdr: INSTANCE=RCS, numregs=c        | |
1139*8bfc4963SZhanjun Dong 	 * | | ____________________________________ | |
1140*8bfc4963SZhanjun Dong 	 * | | | Reglist                          | | |
1141*8bfc4963SZhanjun Dong 	 * | | | - reg1, reg2, ... regc           | | |
1142*8bfc4963SZhanjun Dong 	 * | | |__________________________________| | |
1143*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1144*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1145*8bfc4963SZhanjun Dong 	 * | | Capture4:                            | |
1146*8bfc4963SZhanjun Dong 	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=d| |
1147*8bfc4963SZhanjun Dong 	 * | | ____________________________________ | |
1148*8bfc4963SZhanjun Dong 	 * | | | Reglist                          | | |
1149*8bfc4963SZhanjun Dong 	 * | | | - reg1, reg2, ... regd           | | |
1150*8bfc4963SZhanjun Dong 	 * | | |__________________________________| | |
1151*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1152*8bfc4963SZhanjun Dong 	 * | ________________________________________ |
1153*8bfc4963SZhanjun Dong 	 * | | Capture5:                            | |
1154*8bfc4963SZhanjun Dong 	 * | |  Hdr: INSTANCE=CCS0, numregs=e       | |
1155*8bfc4963SZhanjun Dong 	 * | | ____________________________________ | |
1156*8bfc4963SZhanjun Dong 	 * | | | Reglist                          | | |
1157*8bfc4963SZhanjun Dong 	 * | | | - reg1, reg2, ... rege           | | |
1158*8bfc4963SZhanjun Dong 	 * | | |__________________________________| | |
1159*8bfc4963SZhanjun Dong 	 * | |______________________________________| |
1160*8bfc4963SZhanjun Dong 	 * |__________________________________________|
1161*8bfc4963SZhanjun Dong 	 */
1162*8bfc4963SZhanjun Dong 	is_partial = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE, ghdr.info);
1163*8bfc4963SZhanjun Dong 	numlists = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES, ghdr.info);
1164*8bfc4963SZhanjun Dong 
1165*8bfc4963SZhanjun Dong 	while (numlists--) {
1166*8bfc4963SZhanjun Dong 		if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {
1167*8bfc4963SZhanjun Dong 			ret = -EIO;
1168*8bfc4963SZhanjun Dong 			break;
1169*8bfc4963SZhanjun Dong 		}
1170*8bfc4963SZhanjun Dong 
1171*8bfc4963SZhanjun Dong 		datatype = FIELD_GET(GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE, hdr.info);
1172*8bfc4963SZhanjun Dong 		if (datatype > GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
1173*8bfc4963SZhanjun Dong 			/* unknown capture type - skip over to next capture set */
1174*8bfc4963SZhanjun Dong 			numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
1175*8bfc4963SZhanjun Dong 					    hdr.num_mmio_entries);
1176*8bfc4963SZhanjun Dong 			while (numregs--) {
1177*8bfc4963SZhanjun Dong 				if (guc_capture_log_get_register(guc, buf, &tmp)) {
1178*8bfc4963SZhanjun Dong 					ret = -EIO;
1179*8bfc4963SZhanjun Dong 					break;
1180*8bfc4963SZhanjun Dong 				}
1181*8bfc4963SZhanjun Dong 			}
1182*8bfc4963SZhanjun Dong 			continue;
1183*8bfc4963SZhanjun Dong 		} else if (node) {
1184*8bfc4963SZhanjun Dong 			/*
1185*8bfc4963SZhanjun Dong 			 * Based on the current capture type and what we have so far,
1186*8bfc4963SZhanjun Dong 			 * decide if we should add the current node into the internal
1187*8bfc4963SZhanjun Dong 			 * linked list for match-up when xe_devcoredump calls later
1188*8bfc4963SZhanjun Dong 			 * (and alloc a blank node for the next set of reglists)
1189*8bfc4963SZhanjun Dong 			 * or continue with the same node or clone the current node
1190*8bfc4963SZhanjun Dong 			 * but only retain the global or class registers (such as the
1191*8bfc4963SZhanjun Dong 			 * case of dependent engine resets).
1192*8bfc4963SZhanjun Dong 			 */
1193*8bfc4963SZhanjun Dong 			if (datatype == GUC_STATE_CAPTURE_TYPE_GLOBAL) {
1194*8bfc4963SZhanjun Dong 				guc_capture_add_node_to_outlist(guc->capture, node);
1195*8bfc4963SZhanjun Dong 				node = NULL;
1196*8bfc4963SZhanjun Dong 			} else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
1197*8bfc4963SZhanjun Dong 				   node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS].num_regs) {
1198*8bfc4963SZhanjun Dong 				/* Add to list, clone node and duplicate global list */
1199*8bfc4963SZhanjun Dong 				guc_capture_add_node_to_outlist(guc->capture, node);
1200*8bfc4963SZhanjun Dong 				node = guc_capture_clone_node(guc, node,
1201*8bfc4963SZhanjun Dong 							      GCAP_PARSED_REGLIST_INDEX_GLOBAL);
1202*8bfc4963SZhanjun Dong 			} else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE &&
1203*8bfc4963SZhanjun Dong 				   node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE].num_regs) {
1204*8bfc4963SZhanjun Dong 				/* Add to list, clone node and duplicate global + class lists */
1205*8bfc4963SZhanjun Dong 				guc_capture_add_node_to_outlist(guc->capture, node);
1206*8bfc4963SZhanjun Dong 				node = guc_capture_clone_node(guc, node,
1207*8bfc4963SZhanjun Dong 							      (GCAP_PARSED_REGLIST_INDEX_GLOBAL |
1208*8bfc4963SZhanjun Dong 							      GCAP_PARSED_REGLIST_INDEX_ENGCLASS));
1209*8bfc4963SZhanjun Dong 			}
1210*8bfc4963SZhanjun Dong 		}
1211*8bfc4963SZhanjun Dong 
1212*8bfc4963SZhanjun Dong 		if (!node) {
1213*8bfc4963SZhanjun Dong 			node = guc_capture_get_prealloc_node(guc);
1214*8bfc4963SZhanjun Dong 			if (!node) {
1215*8bfc4963SZhanjun Dong 				ret = -ENOMEM;
1216*8bfc4963SZhanjun Dong 				break;
1217*8bfc4963SZhanjun Dong 			}
1218*8bfc4963SZhanjun Dong 			if (datatype != GUC_STATE_CAPTURE_TYPE_GLOBAL)
1219*8bfc4963SZhanjun Dong 				xe_gt_dbg(gt, "Register capture missing global dump: %08x!\n",
1220*8bfc4963SZhanjun Dong 					  datatype);
1221*8bfc4963SZhanjun Dong 		}
1222*8bfc4963SZhanjun Dong 		node->is_partial = is_partial;
1223*8bfc4963SZhanjun Dong 		node->reginfo[datatype].vfid = FIELD_GET(GUC_STATE_CAPTURE_HEADER_VFID, hdr.owner);
1224*8bfc4963SZhanjun Dong 
1225*8bfc4963SZhanjun Dong 		switch (datatype) {
1226*8bfc4963SZhanjun Dong 		case GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE:
1227*8bfc4963SZhanjun Dong 			node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
1228*8bfc4963SZhanjun Dong 						    hdr.info);
1229*8bfc4963SZhanjun Dong 			node->eng_inst = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE,
1230*8bfc4963SZhanjun Dong 						   hdr.info);
1231*8bfc4963SZhanjun Dong 			node->lrca = hdr.lrca;
1232*8bfc4963SZhanjun Dong 			node->guc_id = hdr.guc_id;
1233*8bfc4963SZhanjun Dong 			break;
1234*8bfc4963SZhanjun Dong 		case GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS:
1235*8bfc4963SZhanjun Dong 			node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
1236*8bfc4963SZhanjun Dong 						    hdr.info);
1237*8bfc4963SZhanjun Dong 			break;
1238*8bfc4963SZhanjun Dong 		default:
1239*8bfc4963SZhanjun Dong 			break;
1240*8bfc4963SZhanjun Dong 		}
1241*8bfc4963SZhanjun Dong 
1242*8bfc4963SZhanjun Dong 		numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
1243*8bfc4963SZhanjun Dong 				    hdr.num_mmio_entries);
1244*8bfc4963SZhanjun Dong 		if (numregs > guc->capture->max_mmio_per_node) {
1245*8bfc4963SZhanjun Dong 			xe_gt_dbg(gt, "Register capture list extraction clipped by prealloc!\n");
1246*8bfc4963SZhanjun Dong 			numregs = guc->capture->max_mmio_per_node;
1247*8bfc4963SZhanjun Dong 		}
1248*8bfc4963SZhanjun Dong 		node->reginfo[datatype].num_regs = numregs;
1249*8bfc4963SZhanjun Dong 		regs = node->reginfo[datatype].regs;
1250*8bfc4963SZhanjun Dong 		i = 0;
1251*8bfc4963SZhanjun Dong 		while (numregs--) {
1252*8bfc4963SZhanjun Dong 			if (guc_capture_log_get_register(guc, buf, &regs[i++])) {
1253*8bfc4963SZhanjun Dong 				ret = -EIO;
1254*8bfc4963SZhanjun Dong 				break;
1255*8bfc4963SZhanjun Dong 			}
1256*8bfc4963SZhanjun Dong 		}
1257*8bfc4963SZhanjun Dong 	}
1258*8bfc4963SZhanjun Dong 
1259*8bfc4963SZhanjun Dong bailout:
1260*8bfc4963SZhanjun Dong 	if (node) {
1261*8bfc4963SZhanjun Dong 		/* If we have data, add to linked list for match-up when xe_devcoredump calls */
1262*8bfc4963SZhanjun Dong 		for (i = GUC_STATE_CAPTURE_TYPE_GLOBAL; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1263*8bfc4963SZhanjun Dong 			if (node->reginfo[i].regs) {
1264*8bfc4963SZhanjun Dong 				guc_capture_add_node_to_outlist(guc->capture, node);
1265*8bfc4963SZhanjun Dong 				node = NULL;
1266*8bfc4963SZhanjun Dong 				break;
1267*8bfc4963SZhanjun Dong 			}
1268*8bfc4963SZhanjun Dong 		}
1269*8bfc4963SZhanjun Dong 		if (node) /* else return it back to cache list */
1270*8bfc4963SZhanjun Dong 			guc_capture_add_node_to_cachelist(guc->capture, node);
1271*8bfc4963SZhanjun Dong 	}
1272*8bfc4963SZhanjun Dong 	return ret;
1273*8bfc4963SZhanjun Dong }
1274*8bfc4963SZhanjun Dong 
1275*8bfc4963SZhanjun Dong static int __guc_capture_flushlog_complete(struct xe_guc *guc)
1276*8bfc4963SZhanjun Dong {
1277*8bfc4963SZhanjun Dong 	u32 action[] = {
1278*8bfc4963SZhanjun Dong 		XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE,
1279*8bfc4963SZhanjun Dong 		GUC_LOG_BUFFER_CAPTURE
1280*8bfc4963SZhanjun Dong 	};
1281*8bfc4963SZhanjun Dong 
1282*8bfc4963SZhanjun Dong 	return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action));
1283*8bfc4963SZhanjun Dong }
1284*8bfc4963SZhanjun Dong 
1285*8bfc4963SZhanjun Dong static void __guc_capture_process_output(struct xe_guc *guc)
1286*8bfc4963SZhanjun Dong {
1287*8bfc4963SZhanjun Dong 	unsigned int buffer_size, read_offset, write_offset, full_count;
1288*8bfc4963SZhanjun Dong 	struct xe_uc *uc = container_of(guc, typeof(*uc), guc);
1289*8bfc4963SZhanjun Dong 	struct guc_log_buffer_state log_buf_state_local;
1290*8bfc4963SZhanjun Dong 	struct __guc_capture_bufstate buf;
1291*8bfc4963SZhanjun Dong 	bool new_overflow;
1292*8bfc4963SZhanjun Dong 	int ret, tmp;
1293*8bfc4963SZhanjun Dong 	u32 log_buf_state_offset;
1294*8bfc4963SZhanjun Dong 	u32 src_data_offset;
1295*8bfc4963SZhanjun Dong 
1296*8bfc4963SZhanjun Dong 	log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_BUFFER_CAPTURE;
1297*8bfc4963SZhanjun Dong 	src_data_offset = xe_guc_get_log_buffer_offset(&guc->log, GUC_LOG_BUFFER_CAPTURE);
1298*8bfc4963SZhanjun Dong 
1299*8bfc4963SZhanjun Dong 	/*
1300*8bfc4963SZhanjun Dong 	 * Make a copy of the state structure, inside GuC log buffer
1301*8bfc4963SZhanjun Dong 	 * (which is uncached mapped), on the stack to avoid reading
1302*8bfc4963SZhanjun Dong 	 * from it multiple times.
1303*8bfc4963SZhanjun Dong 	 */
1304*8bfc4963SZhanjun Dong 	xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap,
1305*8bfc4963SZhanjun Dong 			   log_buf_state_offset, sizeof(struct guc_log_buffer_state));
1306*8bfc4963SZhanjun Dong 
1307*8bfc4963SZhanjun Dong 	buffer_size = xe_guc_get_log_buffer_size(&guc->log, GUC_LOG_BUFFER_CAPTURE);
1308*8bfc4963SZhanjun Dong 	read_offset = log_buf_state_local.read_ptr;
1309*8bfc4963SZhanjun Dong 	write_offset = log_buf_state_local.sampled_write_ptr;
1310*8bfc4963SZhanjun Dong 	full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags);
1311*8bfc4963SZhanjun Dong 
1312*8bfc4963SZhanjun Dong 	/* Bookkeeping stuff */
1313*8bfc4963SZhanjun Dong 	tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags);
1314*8bfc4963SZhanjun Dong 	guc->log.stats[GUC_LOG_BUFFER_CAPTURE].flush += tmp;
1315*8bfc4963SZhanjun Dong 	new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_BUFFER_CAPTURE,
1316*8bfc4963SZhanjun Dong 						     full_count);
1317*8bfc4963SZhanjun Dong 
1318*8bfc4963SZhanjun Dong 	/* Now copy the actual logs. */
1319*8bfc4963SZhanjun Dong 	if (unlikely(new_overflow)) {
1320*8bfc4963SZhanjun Dong 		/* copy the whole buffer in case of overflow */
1321*8bfc4963SZhanjun Dong 		read_offset = 0;
1322*8bfc4963SZhanjun Dong 		write_offset = buffer_size;
1323*8bfc4963SZhanjun Dong 	} else if (unlikely((read_offset > buffer_size) ||
1324*8bfc4963SZhanjun Dong 			(write_offset > buffer_size))) {
1325*8bfc4963SZhanjun Dong 		xe_gt_err(guc_to_gt(guc),
1326*8bfc4963SZhanjun Dong 			  "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n",
1327*8bfc4963SZhanjun Dong 			  read_offset, buffer_size);
1328*8bfc4963SZhanjun Dong 		/* copy whole buffer as offsets are unreliable */
1329*8bfc4963SZhanjun Dong 		read_offset = 0;
1330*8bfc4963SZhanjun Dong 		write_offset = buffer_size;
1331*8bfc4963SZhanjun Dong 	}
1332*8bfc4963SZhanjun Dong 
1333*8bfc4963SZhanjun Dong 	buf.size = buffer_size;
1334*8bfc4963SZhanjun Dong 	buf.rd = read_offset;
1335*8bfc4963SZhanjun Dong 	buf.wr = write_offset;
1336*8bfc4963SZhanjun Dong 	buf.data_offset = src_data_offset;
1337*8bfc4963SZhanjun Dong 
1338*8bfc4963SZhanjun Dong 	if (!xe_guc_read_stopped(guc)) {
1339*8bfc4963SZhanjun Dong 		do {
1340*8bfc4963SZhanjun Dong 			ret = guc_capture_extract_reglists(guc, &buf);
1341*8bfc4963SZhanjun Dong 			if (ret && ret != -ENODATA)
1342*8bfc4963SZhanjun Dong 				xe_gt_dbg(guc_to_gt(guc), "Capture extraction failed:%d\n", ret);
1343*8bfc4963SZhanjun Dong 		} while (ret >= 0);
1344*8bfc4963SZhanjun Dong 	}
1345*8bfc4963SZhanjun Dong 
1346*8bfc4963SZhanjun Dong 	/* Update the state of log buffer err-cap state */
1347*8bfc4963SZhanjun Dong 	xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
1348*8bfc4963SZhanjun Dong 		  log_buf_state_offset + offsetof(struct guc_log_buffer_state, read_ptr), u32,
1349*8bfc4963SZhanjun Dong 		  write_offset);
1350*8bfc4963SZhanjun Dong 
1351*8bfc4963SZhanjun Dong 	/*
1352*8bfc4963SZhanjun Dong 	 * Clear the flush_to_file from local first, the local was loaded by above
1353*8bfc4963SZhanjun Dong 	 * xe_map_memcpy_from, then write out the "updated local" through
1354*8bfc4963SZhanjun Dong 	 * xe_map_wr()
1355*8bfc4963SZhanjun Dong 	 */
1356*8bfc4963SZhanjun Dong 	log_buf_state_local.flags &= ~GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE;
1357*8bfc4963SZhanjun Dong 	xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
1358*8bfc4963SZhanjun Dong 		  log_buf_state_offset + offsetof(struct guc_log_buffer_state, flags), u32,
1359*8bfc4963SZhanjun Dong 		  log_buf_state_local.flags);
1360*8bfc4963SZhanjun Dong 	__guc_capture_flushlog_complete(guc);
1361*8bfc4963SZhanjun Dong }
1362*8bfc4963SZhanjun Dong 
1363*8bfc4963SZhanjun Dong /*
1364*8bfc4963SZhanjun Dong  * xe_guc_capture_process - Process GuC register captured data
1365*8bfc4963SZhanjun Dong  * @guc: The GuC object
1366*8bfc4963SZhanjun Dong  *
1367*8bfc4963SZhanjun Dong  * When GuC captured data is ready, GuC will send message
1368*8bfc4963SZhanjun Dong  * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be
1369*8bfc4963SZhanjun Dong  * called to process the data comes with the message.
1370*8bfc4963SZhanjun Dong  *
1371*8bfc4963SZhanjun Dong  * Returns: None
1372*8bfc4963SZhanjun Dong  */
1373*8bfc4963SZhanjun Dong void xe_guc_capture_process(struct xe_guc *guc)
1374*8bfc4963SZhanjun Dong {
1375*8bfc4963SZhanjun Dong 	if (guc->capture)
1376*8bfc4963SZhanjun Dong 		__guc_capture_process_output(guc);
1377*8bfc4963SZhanjun Dong }
1378*8bfc4963SZhanjun Dong 
1379*8bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
1380*8bfc4963SZhanjun Dong guc_capture_alloc_one_node(struct xe_guc *guc)
1381*8bfc4963SZhanjun Dong {
1382*8bfc4963SZhanjun Dong 	struct drm_device *drm = guc_to_drm(guc);
1383*8bfc4963SZhanjun Dong 	struct __guc_capture_parsed_output *new;
1384*8bfc4963SZhanjun Dong 	int i;
1385*8bfc4963SZhanjun Dong 
1386*8bfc4963SZhanjun Dong 	new = drmm_kzalloc(drm, sizeof(*new), GFP_KERNEL);
1387*8bfc4963SZhanjun Dong 	if (!new)
1388*8bfc4963SZhanjun Dong 		return NULL;
1389*8bfc4963SZhanjun Dong 
1390*8bfc4963SZhanjun Dong 	for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1391*8bfc4963SZhanjun Dong 		new->reginfo[i].regs = drmm_kzalloc(drm, guc->capture->max_mmio_per_node *
1392*8bfc4963SZhanjun Dong 						    sizeof(struct guc_mmio_reg), GFP_KERNEL);
1393*8bfc4963SZhanjun Dong 		if (!new->reginfo[i].regs) {
1394*8bfc4963SZhanjun Dong 			while (i)
1395*8bfc4963SZhanjun Dong 				drmm_kfree(drm, new->reginfo[--i].regs);
1396*8bfc4963SZhanjun Dong 			drmm_kfree(drm, new);
1397*8bfc4963SZhanjun Dong 			return NULL;
1398*8bfc4963SZhanjun Dong 		}
1399*8bfc4963SZhanjun Dong 	}
1400*8bfc4963SZhanjun Dong 	guc_capture_init_node(guc, new);
1401*8bfc4963SZhanjun Dong 
1402*8bfc4963SZhanjun Dong 	return new;
1403*8bfc4963SZhanjun Dong }
1404*8bfc4963SZhanjun Dong 
1405*8bfc4963SZhanjun Dong static void
1406*8bfc4963SZhanjun Dong __guc_capture_create_prealloc_nodes(struct xe_guc *guc)
1407*8bfc4963SZhanjun Dong {
1408*8bfc4963SZhanjun Dong 	struct __guc_capture_parsed_output *node = NULL;
1409*8bfc4963SZhanjun Dong 	int i;
1410*8bfc4963SZhanjun Dong 
1411*8bfc4963SZhanjun Dong 	for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) {
1412*8bfc4963SZhanjun Dong 		node = guc_capture_alloc_one_node(guc);
1413*8bfc4963SZhanjun Dong 		if (!node) {
1414*8bfc4963SZhanjun Dong 			xe_gt_warn(guc_to_gt(guc), "Register capture pre-alloc-cache failure\n");
1415*8bfc4963SZhanjun Dong 			/* dont free the priors, use what we got and cleanup at shutdown */
1416*8bfc4963SZhanjun Dong 			return;
1417*8bfc4963SZhanjun Dong 		}
1418*8bfc4963SZhanjun Dong 		guc_capture_add_node_to_cachelist(guc->capture, node);
1419*8bfc4963SZhanjun Dong 	}
1420*8bfc4963SZhanjun Dong }
1421*8bfc4963SZhanjun Dong 
1422*8bfc4963SZhanjun Dong static int
1423*8bfc4963SZhanjun Dong guc_get_max_reglist_count(struct xe_guc *guc)
1424*8bfc4963SZhanjun Dong {
1425*8bfc4963SZhanjun Dong 	int i, j, k, tmp, maxregcount = 0;
1426*8bfc4963SZhanjun Dong 
1427*8bfc4963SZhanjun Dong 	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {
1428*8bfc4963SZhanjun Dong 		for (j = 0; j < GUC_STATE_CAPTURE_TYPE_MAX; ++j) {
1429*8bfc4963SZhanjun Dong 			for (k = 0; k < GUC_CAPTURE_LIST_CLASS_MAX; ++k) {
1430*8bfc4963SZhanjun Dong 				const struct __guc_mmio_reg_descr_group *match;
1431*8bfc4963SZhanjun Dong 
1432*8bfc4963SZhanjun Dong 				if (j == GUC_STATE_CAPTURE_TYPE_GLOBAL && k > 0)
1433*8bfc4963SZhanjun Dong 					continue;
1434*8bfc4963SZhanjun Dong 
1435*8bfc4963SZhanjun Dong 				tmp = 0;
1436*8bfc4963SZhanjun Dong 				match = guc_capture_get_one_list(guc->capture->reglists, i, j, k);
1437*8bfc4963SZhanjun Dong 				if (match)
1438*8bfc4963SZhanjun Dong 					tmp = match->num_regs;
1439*8bfc4963SZhanjun Dong 
1440*8bfc4963SZhanjun Dong 				match = guc_capture_get_one_list(guc->capture->extlists, i, j, k);
1441*8bfc4963SZhanjun Dong 				if (match)
1442*8bfc4963SZhanjun Dong 					tmp += match->num_regs;
1443*8bfc4963SZhanjun Dong 
1444*8bfc4963SZhanjun Dong 				if (tmp > maxregcount)
1445*8bfc4963SZhanjun Dong 					maxregcount = tmp;
1446*8bfc4963SZhanjun Dong 			}
1447*8bfc4963SZhanjun Dong 		}
1448*8bfc4963SZhanjun Dong 	}
1449*8bfc4963SZhanjun Dong 	if (!maxregcount)
1450*8bfc4963SZhanjun Dong 		maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS;
1451*8bfc4963SZhanjun Dong 
1452*8bfc4963SZhanjun Dong 	return maxregcount;
1453*8bfc4963SZhanjun Dong }
1454*8bfc4963SZhanjun Dong 
1455*8bfc4963SZhanjun Dong static void
1456*8bfc4963SZhanjun Dong guc_capture_create_prealloc_nodes(struct xe_guc *guc)
1457*8bfc4963SZhanjun Dong {
1458*8bfc4963SZhanjun Dong 	/* skip if we've already done the pre-alloc */
1459*8bfc4963SZhanjun Dong 	if (guc->capture->max_mmio_per_node)
1460*8bfc4963SZhanjun Dong 		return;
1461*8bfc4963SZhanjun Dong 
1462*8bfc4963SZhanjun Dong 	guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc);
1463*8bfc4963SZhanjun Dong 	__guc_capture_create_prealloc_nodes(guc);
1464*8bfc4963SZhanjun Dong }
1465*8bfc4963SZhanjun Dong 
1466b170d696SZhanjun Dong /*
1467b170d696SZhanjun Dong  * xe_guc_capture_steered_list_init - Init steering register list
1468b170d696SZhanjun Dong  * @guc: The GuC object
1469b170d696SZhanjun Dong  *
1470*8bfc4963SZhanjun Dong  * Init steering register list for GuC register capture, create pre-alloc node
1471b170d696SZhanjun Dong  */
1472b170d696SZhanjun Dong void xe_guc_capture_steered_list_init(struct xe_guc *guc)
1473b170d696SZhanjun Dong {
1474b170d696SZhanjun Dong 	/*
1475b170d696SZhanjun Dong 	 * For certain engine classes, there are slice and subslice
1476b170d696SZhanjun Dong 	 * level registers requiring steering. We allocate and populate
1477b170d696SZhanjun Dong 	 * these based on hw config and add it as an extension list at
1478b170d696SZhanjun Dong 	 * the end of the pre-populated render list.
1479b170d696SZhanjun Dong 	 */
1480b170d696SZhanjun Dong 	guc_capture_alloc_steered_lists(guc);
148184d15f42SZhanjun Dong 	check_guc_capture_size(guc);
1482*8bfc4963SZhanjun Dong 	guc_capture_create_prealloc_nodes(guc);
1483b170d696SZhanjun Dong }
1484b170d696SZhanjun Dong 
148584d15f42SZhanjun Dong /*
14869c8c7a7eSZhanjun Dong  * xe_guc_capture_init - Init for GuC register capture
14879c8c7a7eSZhanjun Dong  * @guc: The GuC object
14889c8c7a7eSZhanjun Dong  *
14899c8c7a7eSZhanjun Dong  * Init for GuC register capture, alloc memory for capture data structure.
14909c8c7a7eSZhanjun Dong  *
14919c8c7a7eSZhanjun Dong  * Returns: 0 if success.
1492b170d696SZhanjun Dong  *	    -ENOMEM if out of memory
14939c8c7a7eSZhanjun Dong  */
14949c8c7a7eSZhanjun Dong int xe_guc_capture_init(struct xe_guc *guc)
14959c8c7a7eSZhanjun Dong {
14969c8c7a7eSZhanjun Dong 	guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL);
14979c8c7a7eSZhanjun Dong 	if (!guc->capture)
14989c8c7a7eSZhanjun Dong 		return -ENOMEM;
14999c8c7a7eSZhanjun Dong 
15009c8c7a7eSZhanjun Dong 	guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc));
1501*8bfc4963SZhanjun Dong 
1502*8bfc4963SZhanjun Dong 	INIT_LIST_HEAD(&guc->capture->outlist);
1503*8bfc4963SZhanjun Dong 	INIT_LIST_HEAD(&guc->capture->cachelist);
1504*8bfc4963SZhanjun Dong 
15059c8c7a7eSZhanjun Dong 	return 0;
15069c8c7a7eSZhanjun Dong }
1507