xref: /linux/drivers/gpu/drm/xe/xe_guc_capture.c (revision 84d15f426110c9f39cedf499b04d7b3642dca428)
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"
139c8c7a7eSZhanjun Dong #include "regs/xe_engine_regs.h"
149c8c7a7eSZhanjun Dong #include "regs/xe_gt_regs.h"
159c8c7a7eSZhanjun Dong #include "regs/xe_guc_regs.h"
169c8c7a7eSZhanjun Dong #include "regs/xe_regs.h"
179c8c7a7eSZhanjun Dong 
189c8c7a7eSZhanjun Dong #include "xe_bo.h"
199c8c7a7eSZhanjun Dong #include "xe_device.h"
209c8c7a7eSZhanjun Dong #include "xe_exec_queue_types.h"
219c8c7a7eSZhanjun Dong #include "xe_gt.h"
229c8c7a7eSZhanjun Dong #include "xe_gt_mcr.h"
239c8c7a7eSZhanjun Dong #include "xe_gt_printk.h"
249c8c7a7eSZhanjun Dong #include "xe_guc.h"
25*84d15f42SZhanjun Dong #include "xe_guc_ads.h"
269c8c7a7eSZhanjun Dong #include "xe_guc_capture.h"
279c8c7a7eSZhanjun Dong #include "xe_guc_capture_types.h"
289c8c7a7eSZhanjun Dong #include "xe_guc_ct.h"
299c8c7a7eSZhanjun Dong #include "xe_guc_log.h"
309c8c7a7eSZhanjun Dong #include "xe_guc_submit.h"
319c8c7a7eSZhanjun Dong #include "xe_hw_engine_types.h"
329c8c7a7eSZhanjun Dong #include "xe_macros.h"
339c8c7a7eSZhanjun Dong #include "xe_map.h"
349c8c7a7eSZhanjun Dong 
359c8c7a7eSZhanjun Dong /*
369c8c7a7eSZhanjun Dong  * Define all device tables of GuC error capture register lists
379c8c7a7eSZhanjun Dong  * NOTE:
389c8c7a7eSZhanjun Dong  *     For engine-registers, GuC only needs the register offsets
399c8c7a7eSZhanjun Dong  *     from the engine-mmio-base
409c8c7a7eSZhanjun Dong  *
419c8c7a7eSZhanjun Dong  *     64 bit registers need 2 entries for low 32 bit register and high 32 bit
429c8c7a7eSZhanjun Dong  *     register, for example:
439c8c7a7eSZhanjun Dong  *       Register           data_type       flags   mask    Register name
449c8c7a7eSZhanjun Dong  *     { XXX_REG_LO(0),  REG_64BIT_LOW_DW,    0,      0,      NULL},
459c8c7a7eSZhanjun Dong  *     { XXX_REG_HI(0),  REG_64BIT_HI_DW,,    0,      0,      "XXX_REG"},
469c8c7a7eSZhanjun Dong  *     1. data_type: Indicate is hi/low 32 bit for a 64 bit register
479c8c7a7eSZhanjun Dong  *                   A 64 bit register define requires 2 consecutive entries,
489c8c7a7eSZhanjun Dong  *                   with low dword first and hi dword the second.
499c8c7a7eSZhanjun Dong  *     2. Register name: null for incompleted define
509c8c7a7eSZhanjun Dong  */
519c8c7a7eSZhanjun Dong #define COMMON_XELP_BASE_GLOBAL \
529c8c7a7eSZhanjun Dong 	{ FORCEWAKE_GT,			REG_32BIT,	0,	0,	"FORCEWAKE_GT"}
539c8c7a7eSZhanjun Dong 
549c8c7a7eSZhanjun Dong #define COMMON_BASE_ENGINE_INSTANCE \
559c8c7a7eSZhanjun Dong 	{ RING_HWSTAM(0),		REG_32BIT,	0,	0,	"HWSTAM"}, \
569c8c7a7eSZhanjun Dong 	{ RING_HWS_PGA(0),		REG_32BIT,	0,	0,	"RING_HWS_PGA"}, \
579c8c7a7eSZhanjun Dong 	{ RING_HEAD(0),			REG_32BIT,	0,	0,	"RING_HEAD"}, \
589c8c7a7eSZhanjun Dong 	{ RING_TAIL(0),			REG_32BIT,	0,	0,	"RING_TAIL"}, \
599c8c7a7eSZhanjun Dong 	{ RING_CTL(0),			REG_32BIT,	0,	0,	"RING_CTL"}, \
609c8c7a7eSZhanjun Dong 	{ RING_MI_MODE(0),		REG_32BIT,	0,	0,	"RING_MI_MODE"}, \
619c8c7a7eSZhanjun Dong 	{ RING_MODE(0),			REG_32BIT,	0,	0,	"RING_MODE"}, \
629c8c7a7eSZhanjun Dong 	{ RING_ESR(0),			REG_32BIT,	0,	0,	"RING_ESR"}, \
639c8c7a7eSZhanjun Dong 	{ RING_EMR(0),			REG_32BIT,	0,	0,	"RING_EMR"}, \
649c8c7a7eSZhanjun Dong 	{ RING_EIR(0),			REG_32BIT,	0,	0,	"RING_EIR"}, \
659c8c7a7eSZhanjun Dong 	{ RING_IMR(0),			REG_32BIT,	0,	0,	"RING_IMR"}, \
669c8c7a7eSZhanjun Dong 	{ RING_IPEHR(0),		REG_32BIT,	0,	0,	"IPEHR"}, \
679c8c7a7eSZhanjun Dong 	{ RING_INSTDONE(0),		REG_32BIT,	0,	0,	"RING_INSTDONE"}, \
689c8c7a7eSZhanjun Dong 	{ INDIRECT_RING_STATE(0),	REG_32BIT,	0,	0,	"INDIRECT_RING_STATE"}, \
699c8c7a7eSZhanjun Dong 	{ RING_ACTHD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
709c8c7a7eSZhanjun Dong 	{ RING_ACTHD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"ACTHD"}, \
719c8c7a7eSZhanjun Dong 	{ RING_BBADDR(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
729c8c7a7eSZhanjun Dong 	{ RING_BBADDR_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_BBADDR"}, \
739c8c7a7eSZhanjun Dong 	{ RING_START(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
749c8c7a7eSZhanjun Dong 	{ RING_START_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_START"}, \
759c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
769c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_DMA_FADD"}, \
779c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_LO(0),	REG_64BIT_LOW_DW, 0,	0,	NULL}, \
789c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_HI(0),	REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_STATUS"}, \
799c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0,	0,	NULL}, \
809c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_SQ_CONTENTS"}
819c8c7a7eSZhanjun Dong 
829c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS \
839c8c7a7eSZhanjun Dong 	{ RCU_MODE,			REG_32BIT,	0,	0,	"RCU_MODE"}
849c8c7a7eSZhanjun Dong 
859c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS_INSTDONE \
869c8c7a7eSZhanjun Dong 	{ SC_INSTDONE,			REG_32BIT,	0,	0,	"SC_INSTDONE"}, \
879c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA"}, \
889c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA2,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA2"}
899c8c7a7eSZhanjun Dong 
909c8c7a7eSZhanjun Dong #define XELP_VEC_CLASS_REGS \
919c8c7a7eSZhanjun Dong 	{ SFC_DONE(0),			0,	0,	0,	"SFC_DONE[0]"}, \
929c8c7a7eSZhanjun Dong 	{ SFC_DONE(1),			0,	0,	0,	"SFC_DONE[1]"}, \
939c8c7a7eSZhanjun Dong 	{ SFC_DONE(2),			0,	0,	0,	"SFC_DONE[2]"}, \
949c8c7a7eSZhanjun Dong 	{ SFC_DONE(3),			0,	0,	0,	"SFC_DONE[3]"}
959c8c7a7eSZhanjun Dong 
969c8c7a7eSZhanjun Dong /* XE_LP Global */
979c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
989c8c7a7eSZhanjun Dong 	COMMON_XELP_BASE_GLOBAL,
999c8c7a7eSZhanjun Dong };
1009c8c7a7eSZhanjun Dong 
1019c8c7a7eSZhanjun Dong /* Render / Compute Per-Engine-Instance */
1029c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = {
1039c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1049c8c7a7eSZhanjun Dong };
1059c8c7a7eSZhanjun Dong 
1069c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class */
1079c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = {
1089c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
1099c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS_INSTDONE,
1109c8c7a7eSZhanjun Dong };
1119c8c7a7eSZhanjun Dong 
1129c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class for xehpg */
1139c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = {
1149c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
1159c8c7a7eSZhanjun Dong };
1169c8c7a7eSZhanjun Dong 
1179c8c7a7eSZhanjun Dong /* Media Decode/Encode Per-Engine-Instance */
1189c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = {
1199c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1209c8c7a7eSZhanjun Dong };
1219c8c7a7eSZhanjun Dong 
1229c8c7a7eSZhanjun Dong /* Video Enhancement Engine-Class */
1239c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = {
1249c8c7a7eSZhanjun Dong 	XELP_VEC_CLASS_REGS,
1259c8c7a7eSZhanjun Dong };
1269c8c7a7eSZhanjun Dong 
1279c8c7a7eSZhanjun Dong /* Video Enhancement Per-Engine-Instance */
1289c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = {
1299c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1309c8c7a7eSZhanjun Dong };
1319c8c7a7eSZhanjun Dong 
1329c8c7a7eSZhanjun Dong /* Blitter Per-Engine-Instance */
1339c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = {
1349c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1359c8c7a7eSZhanjun Dong };
1369c8c7a7eSZhanjun Dong 
1379c8c7a7eSZhanjun Dong /* XE_LP - GSC Per-Engine-Instance */
1389c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {
1399c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
1409c8c7a7eSZhanjun Dong };
1419c8c7a7eSZhanjun Dong 
1429c8c7a7eSZhanjun Dong /*
1439c8c7a7eSZhanjun Dong  * Empty list to prevent warnings about unknown class/instance types
1449c8c7a7eSZhanjun Dong  * as not all class/instance types have entries on all platforms.
1459c8c7a7eSZhanjun Dong  */
1469c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr empty_regs_list[] = {
1479c8c7a7eSZhanjun Dong };
1489c8c7a7eSZhanjun Dong 
1499c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
1509c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x)
1519c8c7a7eSZhanjun Dong #define MAKE_REGLIST(regslist, regsowner, regstype, class) \
1529c8c7a7eSZhanjun Dong 	{ \
1539c8c7a7eSZhanjun Dong 		regslist, \
1549c8c7a7eSZhanjun Dong 		ARRAY_SIZE(regslist), \
1559c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_OWNER(regsowner), \
1569c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_TYPE(regstype), \
1579c8c7a7eSZhanjun Dong 		class \
1589c8c7a7eSZhanjun Dong 	}
1599c8c7a7eSZhanjun Dong 
1609c8c7a7eSZhanjun Dong /* List of lists for legacy graphic product version < 1255 */
1619c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {
1629c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
1639c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
1649c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
1659c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
1669c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
1679c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
1689c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
1699c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
1709c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
1719c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
1729c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
1739c8c7a7eSZhanjun Dong 	{}
1749c8c7a7eSZhanjun Dong };
1759c8c7a7eSZhanjun Dong 
1769c8c7a7eSZhanjun Dong  /* List of lists for graphic product version >= 1255 */
1779c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = {
1789c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
1799c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
1809c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
1819c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
1829c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
1839c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
1849c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
1859c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
1869c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
1879c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
1889c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
1899c8c7a7eSZhanjun Dong 	{}
1909c8c7a7eSZhanjun Dong };
1919c8c7a7eSZhanjun Dong 
1929c8c7a7eSZhanjun Dong static const char * const capture_list_type_names[] = {
1939c8c7a7eSZhanjun Dong 	"Global",
1949c8c7a7eSZhanjun Dong 	"Class",
1959c8c7a7eSZhanjun Dong 	"Instance",
1969c8c7a7eSZhanjun Dong };
1979c8c7a7eSZhanjun Dong 
1989c8c7a7eSZhanjun Dong static const char * const capture_engine_class_names[] = {
1999c8c7a7eSZhanjun Dong 	"Render/Compute",
2009c8c7a7eSZhanjun Dong 	"Video",
2019c8c7a7eSZhanjun Dong 	"VideoEnhance",
2029c8c7a7eSZhanjun Dong 	"Blitter",
2039c8c7a7eSZhanjun Dong 	"GSC-Other",
2049c8c7a7eSZhanjun Dong };
2059c8c7a7eSZhanjun Dong 
2069c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache {
2079c8c7a7eSZhanjun Dong 	bool is_valid;
2089c8c7a7eSZhanjun Dong 	void *ptr;
2099c8c7a7eSZhanjun Dong 	size_t size;
2109c8c7a7eSZhanjun Dong 	int status;
2119c8c7a7eSZhanjun Dong };
2129c8c7a7eSZhanjun Dong 
2139c8c7a7eSZhanjun Dong struct xe_guc_state_capture {
2149c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists;
215b170d696SZhanjun Dong 	/**
216b170d696SZhanjun Dong 	 * NOTE: steered registers have multiple instances depending on the HW configuration
217b170d696SZhanjun Dong 	 * (slices or dual-sub-slices) and thus depends on HW fuses discovered
218b170d696SZhanjun Dong 	 */
219b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists;
2209c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
2219c8c7a7eSZhanjun Dong 						[GUC_STATE_CAPTURE_TYPE_MAX]
2229c8c7a7eSZhanjun Dong 						[GUC_CAPTURE_LIST_CLASS_MAX];
2239c8c7a7eSZhanjun Dong 	void *ads_null_cache;
2249c8c7a7eSZhanjun Dong };
2259c8c7a7eSZhanjun Dong 
2269c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
2279c8c7a7eSZhanjun Dong guc_capture_get_device_reglist(struct xe_device *xe)
2289c8c7a7eSZhanjun Dong {
2299c8c7a7eSZhanjun Dong 	if (GRAPHICS_VERx100(xe) >= 1255)
2309c8c7a7eSZhanjun Dong 		return xe_hpg_lists;
2319c8c7a7eSZhanjun Dong 	else
2329c8c7a7eSZhanjun Dong 		return xe_lp_lists;
2339c8c7a7eSZhanjun Dong }
2349c8c7a7eSZhanjun Dong 
2359c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
2369c8c7a7eSZhanjun Dong guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
2379c8c7a7eSZhanjun Dong 			 u32 owner, u32 type, enum guc_capture_list_class_type capture_class)
2389c8c7a7eSZhanjun Dong {
2399c8c7a7eSZhanjun Dong 	int i;
2409c8c7a7eSZhanjun Dong 
2419c8c7a7eSZhanjun Dong 	if (!reglists)
2429c8c7a7eSZhanjun Dong 		return NULL;
2439c8c7a7eSZhanjun Dong 
2449c8c7a7eSZhanjun Dong 	for (i = 0; reglists[i].list; ++i) {
2459c8c7a7eSZhanjun Dong 		if (reglists[i].owner == owner && reglists[i].type == type &&
2469c8c7a7eSZhanjun Dong 		    (reglists[i].engine == capture_class ||
2479c8c7a7eSZhanjun Dong 		     reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL))
2489c8c7a7eSZhanjun Dong 			return &reglists[i];
2499c8c7a7eSZhanjun Dong 	}
2509c8c7a7eSZhanjun Dong 
2519c8c7a7eSZhanjun Dong 	return NULL;
2529c8c7a7eSZhanjun Dong }
2539c8c7a7eSZhanjun Dong 
254b170d696SZhanjun Dong struct __ext_steer_reg {
255b170d696SZhanjun Dong 	const char *name;
256b170d696SZhanjun Dong 	struct xe_reg_mcr reg;
257b170d696SZhanjun Dong };
258b170d696SZhanjun Dong 
259b170d696SZhanjun Dong static const struct __ext_steer_reg xe_extregs[] = {
260b170d696SZhanjun Dong 	{"SAMPLER_INSTDONE",		SAMPLER_INSTDONE},
261b170d696SZhanjun Dong 	{"ROW_INSTDONE",		ROW_INSTDONE}
262b170d696SZhanjun Dong };
263b170d696SZhanjun Dong 
264b170d696SZhanjun Dong static const struct __ext_steer_reg xehpg_extregs[] = {
265b170d696SZhanjun Dong 	{"SC_INSTDONE",			XEHPG_SC_INSTDONE},
266b170d696SZhanjun Dong 	{"SC_INSTDONE_EXTRA",		XEHPG_SC_INSTDONE_EXTRA},
267b170d696SZhanjun Dong 	{"SC_INSTDONE_EXTRA2",		XEHPG_SC_INSTDONE_EXTRA2},
268b170d696SZhanjun Dong 	{"INSTDONE_GEOM_SVGUNIT",	XEHPG_INSTDONE_GEOM_SVGUNIT}
269b170d696SZhanjun Dong };
270b170d696SZhanjun Dong 
271b170d696SZhanjun Dong static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
272b170d696SZhanjun Dong 			   const struct __ext_steer_reg *extlist,
273b170d696SZhanjun Dong 			   int slice_id, int subslice_id)
274b170d696SZhanjun Dong {
275b170d696SZhanjun Dong 	if (!ext || !extlist)
276b170d696SZhanjun Dong 		return;
277b170d696SZhanjun Dong 
278b170d696SZhanjun Dong 	ext->reg = XE_REG(extlist->reg.__reg.addr);
279b170d696SZhanjun Dong 	ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1);
280b170d696SZhanjun Dong 	ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
281b170d696SZhanjun Dong 	ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
282b170d696SZhanjun Dong 	ext->regname = extlist->name;
283b170d696SZhanjun Dong }
284b170d696SZhanjun Dong 
285b170d696SZhanjun Dong static int
286b170d696SZhanjun Dong __alloc_ext_regs(struct drm_device *drm, struct __guc_mmio_reg_descr_group *newlist,
287b170d696SZhanjun Dong 		 const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)
288b170d696SZhanjun Dong {
289b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr *list;
290b170d696SZhanjun Dong 
291b170d696SZhanjun Dong 	list = drmm_kzalloc(drm, num_regs * sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
292b170d696SZhanjun Dong 	if (!list)
293b170d696SZhanjun Dong 		return -ENOMEM;
294b170d696SZhanjun Dong 
295b170d696SZhanjun Dong 	newlist->list = list;
296b170d696SZhanjun Dong 	newlist->num_regs = num_regs;
297b170d696SZhanjun Dong 	newlist->owner = rootlist->owner;
298b170d696SZhanjun Dong 	newlist->engine = rootlist->engine;
299b170d696SZhanjun Dong 	newlist->type = rootlist->type;
300b170d696SZhanjun Dong 
301b170d696SZhanjun Dong 	return 0;
302b170d696SZhanjun Dong }
303b170d696SZhanjun Dong 
304b170d696SZhanjun Dong static int guc_capture_get_steer_reg_num(struct xe_device *xe)
305b170d696SZhanjun Dong {
306b170d696SZhanjun Dong 	int num = ARRAY_SIZE(xe_extregs);
307b170d696SZhanjun Dong 
308b170d696SZhanjun Dong 	if (GRAPHICS_VERx100(xe) >= 1255)
309b170d696SZhanjun Dong 		num += ARRAY_SIZE(xehpg_extregs);
310b170d696SZhanjun Dong 
311b170d696SZhanjun Dong 	return num;
312b170d696SZhanjun Dong }
313b170d696SZhanjun Dong 
314b170d696SZhanjun Dong static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
315b170d696SZhanjun Dong {
316b170d696SZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
317b170d696SZhanjun Dong 	u16 slice, subslice;
318b170d696SZhanjun Dong 	int iter, i, total = 0;
319b170d696SZhanjun Dong 	const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists;
320b170d696SZhanjun Dong 	const struct __guc_mmio_reg_descr_group *list;
321b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists;
322b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr *extarray;
323b170d696SZhanjun Dong 	bool has_xehpg_extregs = GRAPHICS_VERx100(gt_to_xe(gt)) >= 1255;
324b170d696SZhanjun Dong 	struct drm_device *drm = &gt_to_xe(gt)->drm;
325b170d696SZhanjun Dong 	bool has_rcs_ccs = false;
326b170d696SZhanjun Dong 	struct xe_hw_engine *hwe;
327b170d696SZhanjun Dong 	enum xe_hw_engine_id id;
328b170d696SZhanjun Dong 
329b170d696SZhanjun Dong 	/*
330b170d696SZhanjun Dong 	 * If GT has no rcs/ccs, no need to alloc steered list.
331b170d696SZhanjun Dong 	 * Currently, only rcs/ccs has steering register, if in the future,
332b170d696SZhanjun Dong 	 * other engine types has steering register, this condition check need
333b170d696SZhanjun Dong 	 * to be extended
334b170d696SZhanjun Dong 	 */
335b170d696SZhanjun Dong 	for_each_hw_engine(hwe, gt, id) {
336b170d696SZhanjun Dong 		if (xe_engine_class_to_guc_capture_class(hwe->class) ==
337b170d696SZhanjun Dong 		    GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
338b170d696SZhanjun Dong 			has_rcs_ccs = true;
339b170d696SZhanjun Dong 			break;
340b170d696SZhanjun Dong 		}
341b170d696SZhanjun Dong 	}
342b170d696SZhanjun Dong 
343b170d696SZhanjun Dong 	if (!has_rcs_ccs)
344b170d696SZhanjun Dong 		return;
345b170d696SZhanjun Dong 
346b170d696SZhanjun Dong 	/* steered registers currently only exist for the render-class */
347b170d696SZhanjun Dong 	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
348b170d696SZhanjun Dong 					GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
349b170d696SZhanjun Dong 					GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE);
350b170d696SZhanjun Dong 	/*
351b170d696SZhanjun Dong 	 * Skip if this platform has no engine class registers or if extlists
352b170d696SZhanjun Dong 	 * was previously allocated
353b170d696SZhanjun Dong 	 */
354b170d696SZhanjun Dong 	if (!list || guc->capture->extlists)
355b170d696SZhanjun Dong 		return;
356b170d696SZhanjun Dong 
357b170d696SZhanjun Dong 	total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) *
358b170d696SZhanjun Dong 		guc_capture_get_steer_reg_num(guc_to_xe(guc));
359b170d696SZhanjun Dong 
360b170d696SZhanjun Dong 	if (!total)
361b170d696SZhanjun Dong 		return;
362b170d696SZhanjun Dong 
363b170d696SZhanjun Dong 	/* allocate an extra for an end marker */
364b170d696SZhanjun Dong 	extlists = drmm_kzalloc(drm, 2 * sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL);
365b170d696SZhanjun Dong 	if (!extlists)
366b170d696SZhanjun Dong 		return;
367b170d696SZhanjun Dong 
368b170d696SZhanjun Dong 	if (__alloc_ext_regs(drm, &extlists[0], list, total)) {
369b170d696SZhanjun Dong 		drmm_kfree(drm, extlists);
370b170d696SZhanjun Dong 		return;
371b170d696SZhanjun Dong 	}
372b170d696SZhanjun Dong 
373b170d696SZhanjun Dong 	/* For steering registers, the list is generated at run-time */
374b170d696SZhanjun Dong 	extarray = (struct __guc_mmio_reg_descr *)extlists[0].list;
375b170d696SZhanjun Dong 	for_each_dss_steering(iter, gt, slice, subslice) {
376b170d696SZhanjun Dong 		for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) {
377b170d696SZhanjun Dong 			__fill_ext_reg(extarray, &xe_extregs[i], slice, subslice);
378b170d696SZhanjun Dong 			++extarray;
379b170d696SZhanjun Dong 		}
380b170d696SZhanjun Dong 
381b170d696SZhanjun Dong 		if (has_xehpg_extregs)
382b170d696SZhanjun Dong 			for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {
383b170d696SZhanjun Dong 				__fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice);
384b170d696SZhanjun Dong 				++extarray;
385b170d696SZhanjun Dong 			}
386b170d696SZhanjun Dong 	}
387b170d696SZhanjun Dong 
388b170d696SZhanjun Dong 	extlists[0].num_regs = total;
389b170d696SZhanjun Dong 
390b170d696SZhanjun Dong 	xe_gt_dbg(guc_to_gt(guc), "capture found %d ext-regs.\n", total);
391b170d696SZhanjun Dong 	guc->capture->extlists = extlists;
392b170d696SZhanjun Dong }
393b170d696SZhanjun Dong 
3949c8c7a7eSZhanjun Dong static int
3959c8c7a7eSZhanjun Dong guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
3969c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr,
3979c8c7a7eSZhanjun Dong 		      u16 num_entries)
3989c8c7a7eSZhanjun Dong {
399b170d696SZhanjun Dong 	u32 ptr_idx = 0, list_idx = 0;
4009c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
401b170d696SZhanjun Dong 	struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;
4029c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
403b170d696SZhanjun Dong 	u32 list_num;
4049c8c7a7eSZhanjun Dong 
4059c8c7a7eSZhanjun Dong 	if (!reglists)
4069c8c7a7eSZhanjun Dong 		return -ENODEV;
4079c8c7a7eSZhanjun Dong 
4089c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(reglists, owner, type, capture_class);
4099c8c7a7eSZhanjun Dong 	if (!match)
4109c8c7a7eSZhanjun Dong 		return -ENODATA;
4119c8c7a7eSZhanjun Dong 
412b170d696SZhanjun Dong 	list_num = match->num_regs;
413b170d696SZhanjun Dong 	for (list_idx = 0; ptr_idx < num_entries && list_idx < list_num; ++list_idx, ++ptr_idx) {
414b170d696SZhanjun Dong 		ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
415b170d696SZhanjun Dong 		ptr[ptr_idx].value = 0xDEADF00D;
416b170d696SZhanjun Dong 		ptr[ptr_idx].flags = match->list[list_idx].flags;
417b170d696SZhanjun Dong 		ptr[ptr_idx].mask = match->list[list_idx].mask;
4189c8c7a7eSZhanjun Dong 	}
4199c8c7a7eSZhanjun Dong 
420b170d696SZhanjun Dong 	match = guc_capture_get_one_list(extlists, owner, type, capture_class);
421b170d696SZhanjun Dong 	if (match)
422b170d696SZhanjun Dong 		for (ptr_idx = list_num, list_idx = 0;
423b170d696SZhanjun Dong 		     ptr_idx < num_entries && list_idx < match->num_regs;
424b170d696SZhanjun Dong 		     ++ptr_idx, ++list_idx) {
425b170d696SZhanjun Dong 			ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
426b170d696SZhanjun Dong 			ptr[ptr_idx].value = 0xDEADF00D;
427b170d696SZhanjun Dong 			ptr[ptr_idx].flags = match->list[list_idx].flags;
428b170d696SZhanjun Dong 			ptr[ptr_idx].mask = match->list[list_idx].mask;
429b170d696SZhanjun Dong 		}
430b170d696SZhanjun Dong 
431b170d696SZhanjun Dong 	if (ptr_idx < num_entries)
432b170d696SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out-of %d.\n",
433b170d696SZhanjun Dong 			  ptr_idx, num_entries);
4349c8c7a7eSZhanjun Dong 
4359c8c7a7eSZhanjun Dong 	return 0;
4369c8c7a7eSZhanjun Dong }
4379c8c7a7eSZhanjun Dong 
4389c8c7a7eSZhanjun Dong static int
4399c8c7a7eSZhanjun Dong guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
4409c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class)
4419c8c7a7eSZhanjun Dong {
4429c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
443b170d696SZhanjun Dong 	int num_regs = 0;
4449c8c7a7eSZhanjun Dong 
4459c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class);
446b170d696SZhanjun Dong 	if (match)
447b170d696SZhanjun Dong 		num_regs = match->num_regs;
4489c8c7a7eSZhanjun Dong 
449b170d696SZhanjun Dong 	match = guc_capture_get_one_list(guc->capture->extlists, owner, type, capture_class);
450b170d696SZhanjun Dong 	if (match)
451b170d696SZhanjun Dong 		num_regs += match->num_regs;
452b170d696SZhanjun Dong 	else
453b170d696SZhanjun Dong 		/* Estimate steering register size for rcs/ccs */
454b170d696SZhanjun Dong 		if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE)
455b170d696SZhanjun Dong 			num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) *
456b170d696SZhanjun Dong 				    XE_MAX_DSS_FUSE_BITS;
457b170d696SZhanjun Dong 
458b170d696SZhanjun Dong 	return num_regs;
4599c8c7a7eSZhanjun Dong }
4609c8c7a7eSZhanjun Dong 
4619c8c7a7eSZhanjun Dong static int
4629c8c7a7eSZhanjun Dong guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
4639c8c7a7eSZhanjun Dong 			enum guc_capture_list_class_type capture_class,
4649c8c7a7eSZhanjun Dong 			size_t *size, bool is_purpose_est)
4659c8c7a7eSZhanjun Dong {
4669c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
4679c8c7a7eSZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
4689c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache;
4699c8c7a7eSZhanjun Dong 	int num_regs;
4709c8c7a7eSZhanjun Dong 
4719c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX);
4729c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX);
4739c8c7a7eSZhanjun Dong 
4749c8c7a7eSZhanjun Dong 	cache = &gc->ads_cache[owner][type][capture_class];
4759c8c7a7eSZhanjun Dong 	if (!gc->reglists) {
4769c8c7a7eSZhanjun Dong 		xe_gt_warn(gt, "No capture reglist for this device\n");
4779c8c7a7eSZhanjun Dong 		return -ENODEV;
4789c8c7a7eSZhanjun Dong 	}
4799c8c7a7eSZhanjun Dong 
4809c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
4819c8c7a7eSZhanjun Dong 		*size = cache->size;
4829c8c7a7eSZhanjun Dong 		return cache->status;
4839c8c7a7eSZhanjun Dong 	}
4849c8c7a7eSZhanjun Dong 
4859c8c7a7eSZhanjun Dong 	if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
4869c8c7a7eSZhanjun Dong 	    !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) {
4879c8c7a7eSZhanjun Dong 		if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL)
4889c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: global!\n");
4899c8c7a7eSZhanjun Dong 		else
4909c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n",
4919c8c7a7eSZhanjun Dong 				   capture_list_type_names[type], type,
4929c8c7a7eSZhanjun Dong 				   capture_engine_class_names[capture_class], capture_class);
4939c8c7a7eSZhanjun Dong 		return -ENODEV;
4949c8c7a7eSZhanjun Dong 	}
4959c8c7a7eSZhanjun Dong 
4969c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
4979c8c7a7eSZhanjun Dong 	/* intentional empty lists can exist depending on hw config */
4989c8c7a7eSZhanjun Dong 	if (!num_regs)
4999c8c7a7eSZhanjun Dong 		return -ENODATA;
5009c8c7a7eSZhanjun Dong 
5019c8c7a7eSZhanjun Dong 	if (size)
5029c8c7a7eSZhanjun Dong 		*size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
5039c8c7a7eSZhanjun Dong 				   (num_regs * sizeof(struct guc_mmio_reg)));
5049c8c7a7eSZhanjun Dong 
5059c8c7a7eSZhanjun Dong 	return 0;
5069c8c7a7eSZhanjun Dong }
5079c8c7a7eSZhanjun Dong 
5089c8c7a7eSZhanjun Dong /**
5099c8c7a7eSZhanjun Dong  * xe_guc_capture_getlistsize - Get list size for owner/type/class combination
5109c8c7a7eSZhanjun Dong  * @guc: The GuC object
5119c8c7a7eSZhanjun Dong  * @owner: PF/VF owner
5129c8c7a7eSZhanjun Dong  * @type: GuC capture register type
5139c8c7a7eSZhanjun Dong  * @capture_class: GuC capture engine class id
5149c8c7a7eSZhanjun Dong  * @size: Point to the size
5159c8c7a7eSZhanjun Dong  *
5169c8c7a7eSZhanjun Dong  * This function will get the list for the owner/type/class combination, and
5179c8c7a7eSZhanjun Dong  * return the page aligned list size.
5189c8c7a7eSZhanjun Dong  *
5199c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
5209c8c7a7eSZhanjun Dong  */
5219c8c7a7eSZhanjun Dong int
5229c8c7a7eSZhanjun Dong xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
5239c8c7a7eSZhanjun Dong 			   enum guc_capture_list_class_type capture_class, size_t *size)
5249c8c7a7eSZhanjun Dong {
5259c8c7a7eSZhanjun Dong 	return guc_capture_getlistsize(guc, owner, type, capture_class, size, false);
5269c8c7a7eSZhanjun Dong }
5279c8c7a7eSZhanjun Dong 
5289c8c7a7eSZhanjun Dong /**
5299c8c7a7eSZhanjun Dong  * xe_guc_capture_getlist - Get register capture list for owner/type/class
5309c8c7a7eSZhanjun Dong  * combination
5319c8c7a7eSZhanjun Dong  * @guc:	The GuC object
5329c8c7a7eSZhanjun Dong  * @owner:	PF/VF owner
5339c8c7a7eSZhanjun Dong  * @type:	GuC capture register type
5349c8c7a7eSZhanjun Dong  * @capture_class:	GuC capture engine class id
5359c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
5369c8c7a7eSZhanjun Dong  *
5379c8c7a7eSZhanjun Dong  * This function will get the register capture list for the owner/type/class
5389c8c7a7eSZhanjun Dong  * combination.
5399c8c7a7eSZhanjun Dong  *
5409c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
5419c8c7a7eSZhanjun Dong  */
5429c8c7a7eSZhanjun Dong int
5439c8c7a7eSZhanjun Dong xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type,
5449c8c7a7eSZhanjun Dong 		       enum guc_capture_list_class_type capture_class, void **outptr)
5459c8c7a7eSZhanjun Dong {
5469c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
5479c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class];
5489c8c7a7eSZhanjun Dong 	struct guc_debug_capture_list *listnode;
5499c8c7a7eSZhanjun Dong 	int ret, num_regs;
5509c8c7a7eSZhanjun Dong 	u8 *caplist, *tmp;
5519c8c7a7eSZhanjun Dong 	size_t size = 0;
5529c8c7a7eSZhanjun Dong 
5539c8c7a7eSZhanjun Dong 	if (!gc->reglists)
5549c8c7a7eSZhanjun Dong 		return -ENODEV;
5559c8c7a7eSZhanjun Dong 
5569c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
5579c8c7a7eSZhanjun Dong 		*outptr = cache->ptr;
5589c8c7a7eSZhanjun Dong 		return cache->status;
5599c8c7a7eSZhanjun Dong 	}
5609c8c7a7eSZhanjun Dong 
5619c8c7a7eSZhanjun Dong 	ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size);
5629c8c7a7eSZhanjun Dong 	if (ret) {
5639c8c7a7eSZhanjun Dong 		cache->is_valid = true;
5649c8c7a7eSZhanjun Dong 		cache->ptr = NULL;
5659c8c7a7eSZhanjun Dong 		cache->size = 0;
5669c8c7a7eSZhanjun Dong 		cache->status = ret;
5679c8c7a7eSZhanjun Dong 		return ret;
5689c8c7a7eSZhanjun Dong 	}
5699c8c7a7eSZhanjun Dong 
5709c8c7a7eSZhanjun Dong 	caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL);
5719c8c7a7eSZhanjun Dong 	if (!caplist)
5729c8c7a7eSZhanjun Dong 		return -ENOMEM;
5739c8c7a7eSZhanjun Dong 
5749c8c7a7eSZhanjun Dong 	/* populate capture list header */
5759c8c7a7eSZhanjun Dong 	tmp = caplist;
5769c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
5779c8c7a7eSZhanjun Dong 	listnode = (struct guc_debug_capture_list *)tmp;
5789c8c7a7eSZhanjun Dong 	listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
5799c8c7a7eSZhanjun Dong 
5809c8c7a7eSZhanjun Dong 	/* populate list of register descriptor */
5819c8c7a7eSZhanjun Dong 	tmp += sizeof(struct guc_debug_capture_list);
5829c8c7a7eSZhanjun Dong 	guc_capture_list_init(guc, owner, type, capture_class,
5839c8c7a7eSZhanjun Dong 			      (struct guc_mmio_reg *)tmp, num_regs);
5849c8c7a7eSZhanjun Dong 
5859c8c7a7eSZhanjun Dong 	/* cache this list */
5869c8c7a7eSZhanjun Dong 	cache->is_valid = true;
5879c8c7a7eSZhanjun Dong 	cache->ptr = caplist;
5889c8c7a7eSZhanjun Dong 	cache->size = size;
5899c8c7a7eSZhanjun Dong 	cache->status = 0;
5909c8c7a7eSZhanjun Dong 
5919c8c7a7eSZhanjun Dong 	*outptr = caplist;
5929c8c7a7eSZhanjun Dong 
5939c8c7a7eSZhanjun Dong 	return 0;
5949c8c7a7eSZhanjun Dong }
5959c8c7a7eSZhanjun Dong 
5969c8c7a7eSZhanjun Dong /**
5979c8c7a7eSZhanjun Dong  * xe_guc_capture_getnullheader - Get a null list for register capture
5989c8c7a7eSZhanjun Dong  * @guc:	The GuC object
5999c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
6009c8c7a7eSZhanjun Dong  * @size:	Point to the size
6019c8c7a7eSZhanjun Dong  *
6029c8c7a7eSZhanjun Dong  * This function will alloc for a null list for register capture.
6039c8c7a7eSZhanjun Dong  *
6049c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
6059c8c7a7eSZhanjun Dong  */
6069c8c7a7eSZhanjun Dong int
6079c8c7a7eSZhanjun Dong xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size)
6089c8c7a7eSZhanjun Dong {
6099c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
6109c8c7a7eSZhanjun Dong 	int tmp = sizeof(u32) * 4;
6119c8c7a7eSZhanjun Dong 	void *null_header;
6129c8c7a7eSZhanjun Dong 
6139c8c7a7eSZhanjun Dong 	if (gc->ads_null_cache) {
6149c8c7a7eSZhanjun Dong 		*outptr = gc->ads_null_cache;
6159c8c7a7eSZhanjun Dong 		*size = tmp;
6169c8c7a7eSZhanjun Dong 		return 0;
6179c8c7a7eSZhanjun Dong 	}
6189c8c7a7eSZhanjun Dong 
6199c8c7a7eSZhanjun Dong 	null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL);
6209c8c7a7eSZhanjun Dong 	if (!null_header)
6219c8c7a7eSZhanjun Dong 		return -ENOMEM;
6229c8c7a7eSZhanjun Dong 
6239c8c7a7eSZhanjun Dong 	gc->ads_null_cache = null_header;
6249c8c7a7eSZhanjun Dong 	*outptr = null_header;
6259c8c7a7eSZhanjun Dong 	*size = tmp;
6269c8c7a7eSZhanjun Dong 
6279c8c7a7eSZhanjun Dong 	return 0;
6289c8c7a7eSZhanjun Dong }
6299c8c7a7eSZhanjun Dong 
6309c8c7a7eSZhanjun Dong /**
6319c8c7a7eSZhanjun Dong  * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture
6329c8c7a7eSZhanjun Dong  * @guc: point to xe_guc structure
6339c8c7a7eSZhanjun Dong  *
6349c8c7a7eSZhanjun Dong  * Calculate the worst size for GuC register capture by including all possible engines classes.
6359c8c7a7eSZhanjun Dong  *
6369c8c7a7eSZhanjun Dong  * Returns: Calculated size
6379c8c7a7eSZhanjun Dong  */
6389c8c7a7eSZhanjun Dong size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
6399c8c7a7eSZhanjun Dong {
6409c8c7a7eSZhanjun Dong 	size_t total_size, class_size, instance_size, global_size;
6419c8c7a7eSZhanjun Dong 	int i, j;
6429c8c7a7eSZhanjun Dong 
6439c8c7a7eSZhanjun Dong 	/*
6449c8c7a7eSZhanjun Dong 	 * This function calculates the worst case register lists size by
6459c8c7a7eSZhanjun Dong 	 * including all possible engines classes. It is called during the
6469c8c7a7eSZhanjun Dong 	 * first of a two-phase GuC (and ADS-population) initialization
6479c8c7a7eSZhanjun Dong 	 * sequence, that is, during the pre-hwconfig phase before we have
6489c8c7a7eSZhanjun Dong 	 * the exact engine fusing info.
6499c8c7a7eSZhanjun Dong 	 */
6509c8c7a7eSZhanjun Dong 	total_size = PAGE_SIZE;	/* Pad a page in front for empty lists */
6519c8c7a7eSZhanjun Dong 	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
6529c8c7a7eSZhanjun Dong 		for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) {
6539c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
6549c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
6559c8c7a7eSZhanjun Dong 						       j, &class_size) < 0)
6569c8c7a7eSZhanjun Dong 				class_size = 0;
6579c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
6589c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
6599c8c7a7eSZhanjun Dong 						       j, &instance_size) < 0)
6609c8c7a7eSZhanjun Dong 				instance_size = 0;
6619c8c7a7eSZhanjun Dong 			total_size += class_size + instance_size;
6629c8c7a7eSZhanjun Dong 		}
6639c8c7a7eSZhanjun Dong 		if (xe_guc_capture_getlistsize(guc, i,
6649c8c7a7eSZhanjun Dong 					       GUC_STATE_CAPTURE_TYPE_GLOBAL,
6659c8c7a7eSZhanjun Dong 					       0, &global_size) < 0)
6669c8c7a7eSZhanjun Dong 			global_size = 0;
6679c8c7a7eSZhanjun Dong 		total_size += global_size;
6689c8c7a7eSZhanjun Dong 	}
6699c8c7a7eSZhanjun Dong 
6709c8c7a7eSZhanjun Dong 	return PAGE_ALIGN(total_size);
6719c8c7a7eSZhanjun Dong }
6729c8c7a7eSZhanjun Dong 
673*84d15f42SZhanjun Dong static int guc_capture_output_size_est(struct xe_guc *guc)
674*84d15f42SZhanjun Dong {
675*84d15f42SZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
676*84d15f42SZhanjun Dong 	struct xe_hw_engine *hwe;
677*84d15f42SZhanjun Dong 	enum xe_hw_engine_id id;
678*84d15f42SZhanjun Dong 
679*84d15f42SZhanjun Dong 	int capture_size = 0;
680*84d15f42SZhanjun Dong 	size_t tmp = 0;
681*84d15f42SZhanjun Dong 
682*84d15f42SZhanjun Dong 	if (!guc->capture)
683*84d15f42SZhanjun Dong 		return -ENODEV;
684*84d15f42SZhanjun Dong 
685*84d15f42SZhanjun Dong 	/*
686*84d15f42SZhanjun Dong 	 * If every single engine-instance suffered a failure in quick succession but
687*84d15f42SZhanjun Dong 	 * were all unrelated, then a burst of multiple error-capture events would dump
688*84d15f42SZhanjun Dong 	 * registers for every one engine instance, one at a time. In this case, GuC
689*84d15f42SZhanjun Dong 	 * would even dump the global-registers repeatedly.
690*84d15f42SZhanjun Dong 	 *
691*84d15f42SZhanjun Dong 	 * For each engine instance, there would be 1 x guc_state_capture_group_t output
692*84d15f42SZhanjun Dong 	 * followed by 3 x guc_state_capture_t lists. The latter is how the register
693*84d15f42SZhanjun Dong 	 * dumps are split across different register types (where the '3' are global vs class
694*84d15f42SZhanjun Dong 	 * vs instance).
695*84d15f42SZhanjun Dong 	 */
696*84d15f42SZhanjun Dong 	for_each_hw_engine(hwe, gt, id) {
697*84d15f42SZhanjun Dong 		enum guc_capture_list_class_type capture_class;
698*84d15f42SZhanjun Dong 
699*84d15f42SZhanjun Dong 		capture_class = xe_engine_class_to_guc_capture_class(hwe->class);
700*84d15f42SZhanjun Dong 		capture_size += sizeof(struct guc_state_capture_group_header_t) +
701*84d15f42SZhanjun Dong 					 (3 * sizeof(struct guc_state_capture_header_t));
702*84d15f42SZhanjun Dong 
703*84d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_GLOBAL,
704*84d15f42SZhanjun Dong 					     0, &tmp, true))
705*84d15f42SZhanjun Dong 			capture_size += tmp;
706*84d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
707*84d15f42SZhanjun Dong 					     capture_class, &tmp, true))
708*84d15f42SZhanjun Dong 			capture_size += tmp;
709*84d15f42SZhanjun Dong 		if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
710*84d15f42SZhanjun Dong 					     capture_class, &tmp, true))
711*84d15f42SZhanjun Dong 			capture_size += tmp;
712*84d15f42SZhanjun Dong 	}
713*84d15f42SZhanjun Dong 
714*84d15f42SZhanjun Dong 	return capture_size;
715*84d15f42SZhanjun Dong }
716*84d15f42SZhanjun Dong 
717*84d15f42SZhanjun Dong /*
718*84d15f42SZhanjun Dong  * Add on a 3x multiplier to allow for multiple back-to-back captures occurring
719*84d15f42SZhanjun Dong  * before the Xe can read the data out and process it
720*84d15f42SZhanjun Dong  */
721*84d15f42SZhanjun Dong #define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
722*84d15f42SZhanjun Dong 
723*84d15f42SZhanjun Dong static void check_guc_capture_size(struct xe_guc *guc)
724*84d15f42SZhanjun Dong {
725*84d15f42SZhanjun Dong 	int capture_size = guc_capture_output_size_est(guc);
726*84d15f42SZhanjun Dong 	int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
727*84d15f42SZhanjun Dong 	u32 buffer_size = xe_guc_log_section_size_capture(&guc->log);
728*84d15f42SZhanjun Dong 
729*84d15f42SZhanjun Dong 	/*
730*84d15f42SZhanjun Dong 	 * NOTE: capture_size is much smaller than the capture region
731*84d15f42SZhanjun Dong 	 * allocation (DG2: <80K vs 1MB).
732*84d15f42SZhanjun Dong 	 * Additionally, its based on space needed to fit all engines getting
733*84d15f42SZhanjun Dong 	 * reset at once within the same G2H handler task slot. This is very
734*84d15f42SZhanjun Dong 	 * unlikely. However, if GuC really does run out of space for whatever
735*84d15f42SZhanjun Dong 	 * reason, we will see an separate warning message when processing the
736*84d15f42SZhanjun Dong 	 * G2H event capture-notification, search for:
737*84d15f42SZhanjun Dong 	 * xe_guc_STATE_CAPTURE_EVENT_STATUS_NOSPACE.
738*84d15f42SZhanjun Dong 	 */
739*84d15f42SZhanjun Dong 	if (capture_size < 0)
740*84d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc),
741*84d15f42SZhanjun Dong 			  "Failed to calculate error state capture buffer minimum size: %d!\n",
742*84d15f42SZhanjun Dong 			  capture_size);
743*84d15f42SZhanjun Dong 	if (capture_size > buffer_size)
744*84d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc), "Error state capture buffer maybe small: %d < %d\n",
745*84d15f42SZhanjun Dong 			  buffer_size, capture_size);
746*84d15f42SZhanjun Dong 	else if (spare_size > buffer_size)
747*84d15f42SZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc),
748*84d15f42SZhanjun Dong 			  "Error state capture buffer lacks spare size: %d < %d (min = %d)\n",
749*84d15f42SZhanjun Dong 			  buffer_size, spare_size, capture_size);
750*84d15f42SZhanjun Dong }
751*84d15f42SZhanjun Dong 
752b170d696SZhanjun Dong /*
753b170d696SZhanjun Dong  * xe_guc_capture_steered_list_init - Init steering register list
754b170d696SZhanjun Dong  * @guc: The GuC object
755b170d696SZhanjun Dong  *
756b170d696SZhanjun Dong  * Init steering register list for GuC register capture
757b170d696SZhanjun Dong  */
758b170d696SZhanjun Dong void xe_guc_capture_steered_list_init(struct xe_guc *guc)
759b170d696SZhanjun Dong {
760b170d696SZhanjun Dong 	/*
761b170d696SZhanjun Dong 	 * For certain engine classes, there are slice and subslice
762b170d696SZhanjun Dong 	 * level registers requiring steering. We allocate and populate
763b170d696SZhanjun Dong 	 * these based on hw config and add it as an extension list at
764b170d696SZhanjun Dong 	 * the end of the pre-populated render list.
765b170d696SZhanjun Dong 	 */
766b170d696SZhanjun Dong 	guc_capture_alloc_steered_lists(guc);
767*84d15f42SZhanjun Dong 	check_guc_capture_size(guc);
768b170d696SZhanjun Dong }
769b170d696SZhanjun Dong 
770*84d15f42SZhanjun Dong /*
7719c8c7a7eSZhanjun Dong  * xe_guc_capture_init - Init for GuC register capture
7729c8c7a7eSZhanjun Dong  * @guc: The GuC object
7739c8c7a7eSZhanjun Dong  *
7749c8c7a7eSZhanjun Dong  * Init for GuC register capture, alloc memory for capture data structure.
7759c8c7a7eSZhanjun Dong  *
7769c8c7a7eSZhanjun Dong  * Returns: 0 if success.
777b170d696SZhanjun Dong  *	    -ENOMEM if out of memory
7789c8c7a7eSZhanjun Dong  */
7799c8c7a7eSZhanjun Dong int xe_guc_capture_init(struct xe_guc *guc)
7809c8c7a7eSZhanjun Dong {
7819c8c7a7eSZhanjun Dong 	guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL);
7829c8c7a7eSZhanjun Dong 	if (!guc->capture)
7839c8c7a7eSZhanjun Dong 		return -ENOMEM;
7849c8c7a7eSZhanjun Dong 
7859c8c7a7eSZhanjun Dong 	guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc));
7869c8c7a7eSZhanjun Dong 	return 0;
7879c8c7a7eSZhanjun Dong }
788