xref: /linux/drivers/gpu/drm/xe/xe_guc_capture.c (revision 9c8c7a7e6f1f55ec28cf0dbfe39a7a797f67be78)
1*9c8c7a7eSZhanjun Dong // SPDX-License-Identifier: MIT
2*9c8c7a7eSZhanjun Dong /*
3*9c8c7a7eSZhanjun Dong  * Copyright © 2021-2024 Intel Corporation
4*9c8c7a7eSZhanjun Dong  */
5*9c8c7a7eSZhanjun Dong 
6*9c8c7a7eSZhanjun Dong #include <linux/types.h>
7*9c8c7a7eSZhanjun Dong 
8*9c8c7a7eSZhanjun Dong #include <drm/drm_managed.h>
9*9c8c7a7eSZhanjun Dong #include <drm/drm_print.h>
10*9c8c7a7eSZhanjun Dong 
11*9c8c7a7eSZhanjun Dong #include "abi/guc_actions_abi.h"
12*9c8c7a7eSZhanjun Dong #include "abi/guc_capture_abi.h"
13*9c8c7a7eSZhanjun Dong #include "regs/xe_engine_regs.h"
14*9c8c7a7eSZhanjun Dong #include "regs/xe_gt_regs.h"
15*9c8c7a7eSZhanjun Dong #include "regs/xe_guc_regs.h"
16*9c8c7a7eSZhanjun Dong #include "regs/xe_regs.h"
17*9c8c7a7eSZhanjun Dong 
18*9c8c7a7eSZhanjun Dong #include "xe_bo.h"
19*9c8c7a7eSZhanjun Dong #include "xe_device.h"
20*9c8c7a7eSZhanjun Dong #include "xe_exec_queue_types.h"
21*9c8c7a7eSZhanjun Dong #include "xe_gt.h"
22*9c8c7a7eSZhanjun Dong #include "xe_gt_mcr.h"
23*9c8c7a7eSZhanjun Dong #include "xe_gt_printk.h"
24*9c8c7a7eSZhanjun Dong #include "xe_guc.h"
25*9c8c7a7eSZhanjun Dong #include "xe_guc_capture.h"
26*9c8c7a7eSZhanjun Dong #include "xe_guc_capture_types.h"
27*9c8c7a7eSZhanjun Dong #include "xe_guc_ct.h"
28*9c8c7a7eSZhanjun Dong #include "xe_guc_log.h"
29*9c8c7a7eSZhanjun Dong #include "xe_guc_submit.h"
30*9c8c7a7eSZhanjun Dong #include "xe_hw_engine_types.h"
31*9c8c7a7eSZhanjun Dong #include "xe_macros.h"
32*9c8c7a7eSZhanjun Dong #include "xe_map.h"
33*9c8c7a7eSZhanjun Dong 
34*9c8c7a7eSZhanjun Dong /*
35*9c8c7a7eSZhanjun Dong  * Define all device tables of GuC error capture register lists
36*9c8c7a7eSZhanjun Dong  * NOTE:
37*9c8c7a7eSZhanjun Dong  *     For engine-registers, GuC only needs the register offsets
38*9c8c7a7eSZhanjun Dong  *     from the engine-mmio-base
39*9c8c7a7eSZhanjun Dong  *
40*9c8c7a7eSZhanjun Dong  *     64 bit registers need 2 entries for low 32 bit register and high 32 bit
41*9c8c7a7eSZhanjun Dong  *     register, for example:
42*9c8c7a7eSZhanjun Dong  *       Register           data_type       flags   mask    Register name
43*9c8c7a7eSZhanjun Dong  *     { XXX_REG_LO(0),  REG_64BIT_LOW_DW,    0,      0,      NULL},
44*9c8c7a7eSZhanjun Dong  *     { XXX_REG_HI(0),  REG_64BIT_HI_DW,,    0,      0,      "XXX_REG"},
45*9c8c7a7eSZhanjun Dong  *     1. data_type: Indicate is hi/low 32 bit for a 64 bit register
46*9c8c7a7eSZhanjun Dong  *                   A 64 bit register define requires 2 consecutive entries,
47*9c8c7a7eSZhanjun Dong  *                   with low dword first and hi dword the second.
48*9c8c7a7eSZhanjun Dong  *     2. Register name: null for incompleted define
49*9c8c7a7eSZhanjun Dong  */
50*9c8c7a7eSZhanjun Dong #define COMMON_XELP_BASE_GLOBAL \
51*9c8c7a7eSZhanjun Dong 	{ FORCEWAKE_GT,			REG_32BIT,	0,	0,	"FORCEWAKE_GT"}
52*9c8c7a7eSZhanjun Dong 
53*9c8c7a7eSZhanjun Dong #define COMMON_BASE_ENGINE_INSTANCE \
54*9c8c7a7eSZhanjun Dong 	{ RING_HWSTAM(0),		REG_32BIT,	0,	0,	"HWSTAM"}, \
55*9c8c7a7eSZhanjun Dong 	{ RING_HWS_PGA(0),		REG_32BIT,	0,	0,	"RING_HWS_PGA"}, \
56*9c8c7a7eSZhanjun Dong 	{ RING_HEAD(0),			REG_32BIT,	0,	0,	"RING_HEAD"}, \
57*9c8c7a7eSZhanjun Dong 	{ RING_TAIL(0),			REG_32BIT,	0,	0,	"RING_TAIL"}, \
58*9c8c7a7eSZhanjun Dong 	{ RING_CTL(0),			REG_32BIT,	0,	0,	"RING_CTL"}, \
59*9c8c7a7eSZhanjun Dong 	{ RING_MI_MODE(0),		REG_32BIT,	0,	0,	"RING_MI_MODE"}, \
60*9c8c7a7eSZhanjun Dong 	{ RING_MODE(0),			REG_32BIT,	0,	0,	"RING_MODE"}, \
61*9c8c7a7eSZhanjun Dong 	{ RING_ESR(0),			REG_32BIT,	0,	0,	"RING_ESR"}, \
62*9c8c7a7eSZhanjun Dong 	{ RING_EMR(0),			REG_32BIT,	0,	0,	"RING_EMR"}, \
63*9c8c7a7eSZhanjun Dong 	{ RING_EIR(0),			REG_32BIT,	0,	0,	"RING_EIR"}, \
64*9c8c7a7eSZhanjun Dong 	{ RING_IMR(0),			REG_32BIT,	0,	0,	"RING_IMR"}, \
65*9c8c7a7eSZhanjun Dong 	{ RING_IPEHR(0),		REG_32BIT,	0,	0,	"IPEHR"}, \
66*9c8c7a7eSZhanjun Dong 	{ RING_INSTDONE(0),		REG_32BIT,	0,	0,	"RING_INSTDONE"}, \
67*9c8c7a7eSZhanjun Dong 	{ INDIRECT_RING_STATE(0),	REG_32BIT,	0,	0,	"INDIRECT_RING_STATE"}, \
68*9c8c7a7eSZhanjun Dong 	{ RING_ACTHD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
69*9c8c7a7eSZhanjun Dong 	{ RING_ACTHD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"ACTHD"}, \
70*9c8c7a7eSZhanjun Dong 	{ RING_BBADDR(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
71*9c8c7a7eSZhanjun Dong 	{ RING_BBADDR_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_BBADDR"}, \
72*9c8c7a7eSZhanjun Dong 	{ RING_START(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
73*9c8c7a7eSZhanjun Dong 	{ RING_START_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_START"}, \
74*9c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD(0),		REG_64BIT_LOW_DW, 0,	0,	NULL}, \
75*9c8c7a7eSZhanjun Dong 	{ RING_DMA_FADD_UDW(0),		REG_64BIT_HI_DW, 0,	0,	"RING_DMA_FADD"}, \
76*9c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_LO(0),	REG_64BIT_LOW_DW, 0,	0,	NULL}, \
77*9c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_STATUS_HI(0),	REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_STATUS"}, \
78*9c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0,	0,	NULL}, \
79*9c8c7a7eSZhanjun Dong 	{ RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0,	0,	"RING_EXECLIST_SQ_CONTENTS"}
80*9c8c7a7eSZhanjun Dong 
81*9c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS \
82*9c8c7a7eSZhanjun Dong 	{ RCU_MODE,			REG_32BIT,	0,	0,	"RCU_MODE"}
83*9c8c7a7eSZhanjun Dong 
84*9c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS_INSTDONE \
85*9c8c7a7eSZhanjun Dong 	{ SC_INSTDONE,			REG_32BIT,	0,	0,	"SC_INSTDONE"}, \
86*9c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA"}, \
87*9c8c7a7eSZhanjun Dong 	{ SC_INSTDONE_EXTRA2,		REG_32BIT,	0,	0,	"SC_INSTDONE_EXTRA2"}
88*9c8c7a7eSZhanjun Dong 
89*9c8c7a7eSZhanjun Dong #define XELP_VEC_CLASS_REGS \
90*9c8c7a7eSZhanjun Dong 	{ SFC_DONE(0),			0,	0,	0,	"SFC_DONE[0]"}, \
91*9c8c7a7eSZhanjun Dong 	{ SFC_DONE(1),			0,	0,	0,	"SFC_DONE[1]"}, \
92*9c8c7a7eSZhanjun Dong 	{ SFC_DONE(2),			0,	0,	0,	"SFC_DONE[2]"}, \
93*9c8c7a7eSZhanjun Dong 	{ SFC_DONE(3),			0,	0,	0,	"SFC_DONE[3]"}
94*9c8c7a7eSZhanjun Dong 
95*9c8c7a7eSZhanjun Dong /* XE_LP Global */
96*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
97*9c8c7a7eSZhanjun Dong 	COMMON_XELP_BASE_GLOBAL,
98*9c8c7a7eSZhanjun Dong };
99*9c8c7a7eSZhanjun Dong 
100*9c8c7a7eSZhanjun Dong /* Render / Compute Per-Engine-Instance */
101*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = {
102*9c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
103*9c8c7a7eSZhanjun Dong };
104*9c8c7a7eSZhanjun Dong 
105*9c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class */
106*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = {
107*9c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
108*9c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS_INSTDONE,
109*9c8c7a7eSZhanjun Dong };
110*9c8c7a7eSZhanjun Dong 
111*9c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class for xehpg */
112*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = {
113*9c8c7a7eSZhanjun Dong 	COMMON_XELP_RC_CLASS,
114*9c8c7a7eSZhanjun Dong };
115*9c8c7a7eSZhanjun Dong 
116*9c8c7a7eSZhanjun Dong /* Media Decode/Encode Per-Engine-Instance */
117*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = {
118*9c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
119*9c8c7a7eSZhanjun Dong };
120*9c8c7a7eSZhanjun Dong 
121*9c8c7a7eSZhanjun Dong /* Video Enhancement Engine-Class */
122*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = {
123*9c8c7a7eSZhanjun Dong 	XELP_VEC_CLASS_REGS,
124*9c8c7a7eSZhanjun Dong };
125*9c8c7a7eSZhanjun Dong 
126*9c8c7a7eSZhanjun Dong /* Video Enhancement Per-Engine-Instance */
127*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = {
128*9c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
129*9c8c7a7eSZhanjun Dong };
130*9c8c7a7eSZhanjun Dong 
131*9c8c7a7eSZhanjun Dong /* Blitter Per-Engine-Instance */
132*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = {
133*9c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
134*9c8c7a7eSZhanjun Dong };
135*9c8c7a7eSZhanjun Dong 
136*9c8c7a7eSZhanjun Dong /* XE_LP - GSC Per-Engine-Instance */
137*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {
138*9c8c7a7eSZhanjun Dong 	COMMON_BASE_ENGINE_INSTANCE,
139*9c8c7a7eSZhanjun Dong };
140*9c8c7a7eSZhanjun Dong 
141*9c8c7a7eSZhanjun Dong /*
142*9c8c7a7eSZhanjun Dong  * Empty list to prevent warnings about unknown class/instance types
143*9c8c7a7eSZhanjun Dong  * as not all class/instance types have entries on all platforms.
144*9c8c7a7eSZhanjun Dong  */
145*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr empty_regs_list[] = {
146*9c8c7a7eSZhanjun Dong };
147*9c8c7a7eSZhanjun Dong 
148*9c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
149*9c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x)
150*9c8c7a7eSZhanjun Dong #define MAKE_REGLIST(regslist, regsowner, regstype, class) \
151*9c8c7a7eSZhanjun Dong 	{ \
152*9c8c7a7eSZhanjun Dong 		regslist, \
153*9c8c7a7eSZhanjun Dong 		ARRAY_SIZE(regslist), \
154*9c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_OWNER(regsowner), \
155*9c8c7a7eSZhanjun Dong 		TO_GCAP_DEF_TYPE(regstype), \
156*9c8c7a7eSZhanjun Dong 		class \
157*9c8c7a7eSZhanjun Dong 	}
158*9c8c7a7eSZhanjun Dong 
159*9c8c7a7eSZhanjun Dong /* List of lists for legacy graphic product version < 1255 */
160*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {
161*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
162*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
163*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
164*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
165*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
166*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
167*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
168*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
169*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
170*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
171*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
172*9c8c7a7eSZhanjun Dong 	{}
173*9c8c7a7eSZhanjun Dong };
174*9c8c7a7eSZhanjun Dong 
175*9c8c7a7eSZhanjun Dong  /* List of lists for graphic product version >= 1255 */
176*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = {
177*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
178*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
179*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
180*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
181*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
182*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
183*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
184*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
185*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
186*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
187*9c8c7a7eSZhanjun Dong 	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
188*9c8c7a7eSZhanjun Dong 	{}
189*9c8c7a7eSZhanjun Dong };
190*9c8c7a7eSZhanjun Dong 
191*9c8c7a7eSZhanjun Dong static const char * const capture_list_type_names[] = {
192*9c8c7a7eSZhanjun Dong 	"Global",
193*9c8c7a7eSZhanjun Dong 	"Class",
194*9c8c7a7eSZhanjun Dong 	"Instance",
195*9c8c7a7eSZhanjun Dong };
196*9c8c7a7eSZhanjun Dong 
197*9c8c7a7eSZhanjun Dong static const char * const capture_engine_class_names[] = {
198*9c8c7a7eSZhanjun Dong 	"Render/Compute",
199*9c8c7a7eSZhanjun Dong 	"Video",
200*9c8c7a7eSZhanjun Dong 	"VideoEnhance",
201*9c8c7a7eSZhanjun Dong 	"Blitter",
202*9c8c7a7eSZhanjun Dong 	"GSC-Other",
203*9c8c7a7eSZhanjun Dong };
204*9c8c7a7eSZhanjun Dong 
205*9c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache {
206*9c8c7a7eSZhanjun Dong 	bool is_valid;
207*9c8c7a7eSZhanjun Dong 	void *ptr;
208*9c8c7a7eSZhanjun Dong 	size_t size;
209*9c8c7a7eSZhanjun Dong 	int status;
210*9c8c7a7eSZhanjun Dong };
211*9c8c7a7eSZhanjun Dong 
212*9c8c7a7eSZhanjun Dong struct xe_guc_state_capture {
213*9c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists;
214*9c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
215*9c8c7a7eSZhanjun Dong 						[GUC_STATE_CAPTURE_TYPE_MAX]
216*9c8c7a7eSZhanjun Dong 						[GUC_CAPTURE_LIST_CLASS_MAX];
217*9c8c7a7eSZhanjun Dong 	void *ads_null_cache;
218*9c8c7a7eSZhanjun Dong };
219*9c8c7a7eSZhanjun Dong 
220*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
221*9c8c7a7eSZhanjun Dong guc_capture_get_device_reglist(struct xe_device *xe)
222*9c8c7a7eSZhanjun Dong {
223*9c8c7a7eSZhanjun Dong 	if (GRAPHICS_VERx100(xe) >= 1255)
224*9c8c7a7eSZhanjun Dong 		return xe_hpg_lists;
225*9c8c7a7eSZhanjun Dong 	else
226*9c8c7a7eSZhanjun Dong 		return xe_lp_lists;
227*9c8c7a7eSZhanjun Dong }
228*9c8c7a7eSZhanjun Dong 
229*9c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
230*9c8c7a7eSZhanjun Dong guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
231*9c8c7a7eSZhanjun Dong 			 u32 owner, u32 type, enum guc_capture_list_class_type capture_class)
232*9c8c7a7eSZhanjun Dong {
233*9c8c7a7eSZhanjun Dong 	int i;
234*9c8c7a7eSZhanjun Dong 
235*9c8c7a7eSZhanjun Dong 	if (!reglists)
236*9c8c7a7eSZhanjun Dong 		return NULL;
237*9c8c7a7eSZhanjun Dong 
238*9c8c7a7eSZhanjun Dong 	for (i = 0; reglists[i].list; ++i) {
239*9c8c7a7eSZhanjun Dong 		if (reglists[i].owner == owner && reglists[i].type == type &&
240*9c8c7a7eSZhanjun Dong 		    (reglists[i].engine == capture_class ||
241*9c8c7a7eSZhanjun Dong 		     reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL))
242*9c8c7a7eSZhanjun Dong 			return &reglists[i];
243*9c8c7a7eSZhanjun Dong 	}
244*9c8c7a7eSZhanjun Dong 
245*9c8c7a7eSZhanjun Dong 	return NULL;
246*9c8c7a7eSZhanjun Dong }
247*9c8c7a7eSZhanjun Dong 
248*9c8c7a7eSZhanjun Dong static int
249*9c8c7a7eSZhanjun Dong guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
250*9c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr,
251*9c8c7a7eSZhanjun Dong 		      u16 num_entries)
252*9c8c7a7eSZhanjun Dong {
253*9c8c7a7eSZhanjun Dong 	u32 i = 0;
254*9c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
255*9c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
256*9c8c7a7eSZhanjun Dong 
257*9c8c7a7eSZhanjun Dong 	if (!reglists)
258*9c8c7a7eSZhanjun Dong 		return -ENODEV;
259*9c8c7a7eSZhanjun Dong 
260*9c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(reglists, owner, type, capture_class);
261*9c8c7a7eSZhanjun Dong 	if (!match)
262*9c8c7a7eSZhanjun Dong 		return -ENODATA;
263*9c8c7a7eSZhanjun Dong 
264*9c8c7a7eSZhanjun Dong 	for (i = 0; i < num_entries && i < match->num_regs; ++i) {
265*9c8c7a7eSZhanjun Dong 		ptr[i].offset = match->list[i].reg.addr;
266*9c8c7a7eSZhanjun Dong 		ptr[i].value = 0xDEADF00D;
267*9c8c7a7eSZhanjun Dong 		ptr[i].flags = match->list[i].flags;
268*9c8c7a7eSZhanjun Dong 		ptr[i].mask = match->list[i].mask;
269*9c8c7a7eSZhanjun Dong 	}
270*9c8c7a7eSZhanjun Dong 
271*9c8c7a7eSZhanjun Dong 	if (i < num_entries)
272*9c8c7a7eSZhanjun Dong 		xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out %d.\n", i,
273*9c8c7a7eSZhanjun Dong 			  num_entries);
274*9c8c7a7eSZhanjun Dong 
275*9c8c7a7eSZhanjun Dong 	return 0;
276*9c8c7a7eSZhanjun Dong }
277*9c8c7a7eSZhanjun Dong 
278*9c8c7a7eSZhanjun Dong static int
279*9c8c7a7eSZhanjun Dong guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
280*9c8c7a7eSZhanjun Dong 		      enum guc_capture_list_class_type capture_class)
281*9c8c7a7eSZhanjun Dong {
282*9c8c7a7eSZhanjun Dong 	const struct __guc_mmio_reg_descr_group *match;
283*9c8c7a7eSZhanjun Dong 
284*9c8c7a7eSZhanjun Dong 	match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class);
285*9c8c7a7eSZhanjun Dong 	if (!match)
286*9c8c7a7eSZhanjun Dong 		return 0;
287*9c8c7a7eSZhanjun Dong 
288*9c8c7a7eSZhanjun Dong 	return match->num_regs;
289*9c8c7a7eSZhanjun Dong }
290*9c8c7a7eSZhanjun Dong 
291*9c8c7a7eSZhanjun Dong static int
292*9c8c7a7eSZhanjun Dong guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
293*9c8c7a7eSZhanjun Dong 			enum guc_capture_list_class_type capture_class,
294*9c8c7a7eSZhanjun Dong 			size_t *size, bool is_purpose_est)
295*9c8c7a7eSZhanjun Dong {
296*9c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
297*9c8c7a7eSZhanjun Dong 	struct xe_gt *gt = guc_to_gt(guc);
298*9c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache;
299*9c8c7a7eSZhanjun Dong 	int num_regs;
300*9c8c7a7eSZhanjun Dong 
301*9c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX);
302*9c8c7a7eSZhanjun Dong 	xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX);
303*9c8c7a7eSZhanjun Dong 
304*9c8c7a7eSZhanjun Dong 	cache = &gc->ads_cache[owner][type][capture_class];
305*9c8c7a7eSZhanjun Dong 	if (!gc->reglists) {
306*9c8c7a7eSZhanjun Dong 		xe_gt_warn(gt, "No capture reglist for this device\n");
307*9c8c7a7eSZhanjun Dong 		return -ENODEV;
308*9c8c7a7eSZhanjun Dong 	}
309*9c8c7a7eSZhanjun Dong 
310*9c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
311*9c8c7a7eSZhanjun Dong 		*size = cache->size;
312*9c8c7a7eSZhanjun Dong 		return cache->status;
313*9c8c7a7eSZhanjun Dong 	}
314*9c8c7a7eSZhanjun Dong 
315*9c8c7a7eSZhanjun Dong 	if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
316*9c8c7a7eSZhanjun Dong 	    !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) {
317*9c8c7a7eSZhanjun Dong 		if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL)
318*9c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: global!\n");
319*9c8c7a7eSZhanjun Dong 		else
320*9c8c7a7eSZhanjun Dong 			xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n",
321*9c8c7a7eSZhanjun Dong 				   capture_list_type_names[type], type,
322*9c8c7a7eSZhanjun Dong 				   capture_engine_class_names[capture_class], capture_class);
323*9c8c7a7eSZhanjun Dong 		return -ENODEV;
324*9c8c7a7eSZhanjun Dong 	}
325*9c8c7a7eSZhanjun Dong 
326*9c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
327*9c8c7a7eSZhanjun Dong 	/* intentional empty lists can exist depending on hw config */
328*9c8c7a7eSZhanjun Dong 	if (!num_regs)
329*9c8c7a7eSZhanjun Dong 		return -ENODATA;
330*9c8c7a7eSZhanjun Dong 
331*9c8c7a7eSZhanjun Dong 	if (size)
332*9c8c7a7eSZhanjun Dong 		*size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
333*9c8c7a7eSZhanjun Dong 				   (num_regs * sizeof(struct guc_mmio_reg)));
334*9c8c7a7eSZhanjun Dong 
335*9c8c7a7eSZhanjun Dong 	return 0;
336*9c8c7a7eSZhanjun Dong }
337*9c8c7a7eSZhanjun Dong 
338*9c8c7a7eSZhanjun Dong /**
339*9c8c7a7eSZhanjun Dong  * xe_guc_capture_getlistsize - Get list size for owner/type/class combination
340*9c8c7a7eSZhanjun Dong  * @guc: The GuC object
341*9c8c7a7eSZhanjun Dong  * @owner: PF/VF owner
342*9c8c7a7eSZhanjun Dong  * @type: GuC capture register type
343*9c8c7a7eSZhanjun Dong  * @capture_class: GuC capture engine class id
344*9c8c7a7eSZhanjun Dong  * @size: Point to the size
345*9c8c7a7eSZhanjun Dong  *
346*9c8c7a7eSZhanjun Dong  * This function will get the list for the owner/type/class combination, and
347*9c8c7a7eSZhanjun Dong  * return the page aligned list size.
348*9c8c7a7eSZhanjun Dong  *
349*9c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
350*9c8c7a7eSZhanjun Dong  */
351*9c8c7a7eSZhanjun Dong int
352*9c8c7a7eSZhanjun Dong xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
353*9c8c7a7eSZhanjun Dong 			   enum guc_capture_list_class_type capture_class, size_t *size)
354*9c8c7a7eSZhanjun Dong {
355*9c8c7a7eSZhanjun Dong 	return guc_capture_getlistsize(guc, owner, type, capture_class, size, false);
356*9c8c7a7eSZhanjun Dong }
357*9c8c7a7eSZhanjun Dong 
358*9c8c7a7eSZhanjun Dong /**
359*9c8c7a7eSZhanjun Dong  * xe_guc_capture_getlist - Get register capture list for owner/type/class
360*9c8c7a7eSZhanjun Dong  * combination
361*9c8c7a7eSZhanjun Dong  * @guc:	The GuC object
362*9c8c7a7eSZhanjun Dong  * @owner:	PF/VF owner
363*9c8c7a7eSZhanjun Dong  * @type:	GuC capture register type
364*9c8c7a7eSZhanjun Dong  * @capture_class:	GuC capture engine class id
365*9c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
366*9c8c7a7eSZhanjun Dong  *
367*9c8c7a7eSZhanjun Dong  * This function will get the register capture list for the owner/type/class
368*9c8c7a7eSZhanjun Dong  * combination.
369*9c8c7a7eSZhanjun Dong  *
370*9c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
371*9c8c7a7eSZhanjun Dong  */
372*9c8c7a7eSZhanjun Dong int
373*9c8c7a7eSZhanjun Dong xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type,
374*9c8c7a7eSZhanjun Dong 		       enum guc_capture_list_class_type capture_class, void **outptr)
375*9c8c7a7eSZhanjun Dong {
376*9c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
377*9c8c7a7eSZhanjun Dong 	struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class];
378*9c8c7a7eSZhanjun Dong 	struct guc_debug_capture_list *listnode;
379*9c8c7a7eSZhanjun Dong 	int ret, num_regs;
380*9c8c7a7eSZhanjun Dong 	u8 *caplist, *tmp;
381*9c8c7a7eSZhanjun Dong 	size_t size = 0;
382*9c8c7a7eSZhanjun Dong 
383*9c8c7a7eSZhanjun Dong 	if (!gc->reglists)
384*9c8c7a7eSZhanjun Dong 		return -ENODEV;
385*9c8c7a7eSZhanjun Dong 
386*9c8c7a7eSZhanjun Dong 	if (cache->is_valid) {
387*9c8c7a7eSZhanjun Dong 		*outptr = cache->ptr;
388*9c8c7a7eSZhanjun Dong 		return cache->status;
389*9c8c7a7eSZhanjun Dong 	}
390*9c8c7a7eSZhanjun Dong 
391*9c8c7a7eSZhanjun Dong 	ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size);
392*9c8c7a7eSZhanjun Dong 	if (ret) {
393*9c8c7a7eSZhanjun Dong 		cache->is_valid = true;
394*9c8c7a7eSZhanjun Dong 		cache->ptr = NULL;
395*9c8c7a7eSZhanjun Dong 		cache->size = 0;
396*9c8c7a7eSZhanjun Dong 		cache->status = ret;
397*9c8c7a7eSZhanjun Dong 		return ret;
398*9c8c7a7eSZhanjun Dong 	}
399*9c8c7a7eSZhanjun Dong 
400*9c8c7a7eSZhanjun Dong 	caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL);
401*9c8c7a7eSZhanjun Dong 	if (!caplist)
402*9c8c7a7eSZhanjun Dong 		return -ENOMEM;
403*9c8c7a7eSZhanjun Dong 
404*9c8c7a7eSZhanjun Dong 	/* populate capture list header */
405*9c8c7a7eSZhanjun Dong 	tmp = caplist;
406*9c8c7a7eSZhanjun Dong 	num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
407*9c8c7a7eSZhanjun Dong 	listnode = (struct guc_debug_capture_list *)tmp;
408*9c8c7a7eSZhanjun Dong 	listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
409*9c8c7a7eSZhanjun Dong 
410*9c8c7a7eSZhanjun Dong 	/* populate list of register descriptor */
411*9c8c7a7eSZhanjun Dong 	tmp += sizeof(struct guc_debug_capture_list);
412*9c8c7a7eSZhanjun Dong 	guc_capture_list_init(guc, owner, type, capture_class,
413*9c8c7a7eSZhanjun Dong 			      (struct guc_mmio_reg *)tmp, num_regs);
414*9c8c7a7eSZhanjun Dong 
415*9c8c7a7eSZhanjun Dong 	/* cache this list */
416*9c8c7a7eSZhanjun Dong 	cache->is_valid = true;
417*9c8c7a7eSZhanjun Dong 	cache->ptr = caplist;
418*9c8c7a7eSZhanjun Dong 	cache->size = size;
419*9c8c7a7eSZhanjun Dong 	cache->status = 0;
420*9c8c7a7eSZhanjun Dong 
421*9c8c7a7eSZhanjun Dong 	*outptr = caplist;
422*9c8c7a7eSZhanjun Dong 
423*9c8c7a7eSZhanjun Dong 	return 0;
424*9c8c7a7eSZhanjun Dong }
425*9c8c7a7eSZhanjun Dong 
426*9c8c7a7eSZhanjun Dong /**
427*9c8c7a7eSZhanjun Dong  * xe_guc_capture_getnullheader - Get a null list for register capture
428*9c8c7a7eSZhanjun Dong  * @guc:	The GuC object
429*9c8c7a7eSZhanjun Dong  * @outptr:	Point to cached register capture list
430*9c8c7a7eSZhanjun Dong  * @size:	Point to the size
431*9c8c7a7eSZhanjun Dong  *
432*9c8c7a7eSZhanjun Dong  * This function will alloc for a null list for register capture.
433*9c8c7a7eSZhanjun Dong  *
434*9c8c7a7eSZhanjun Dong  * Returns: 0 on success or a negative error code on failure.
435*9c8c7a7eSZhanjun Dong  */
436*9c8c7a7eSZhanjun Dong int
437*9c8c7a7eSZhanjun Dong xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size)
438*9c8c7a7eSZhanjun Dong {
439*9c8c7a7eSZhanjun Dong 	struct xe_guc_state_capture *gc = guc->capture;
440*9c8c7a7eSZhanjun Dong 	int tmp = sizeof(u32) * 4;
441*9c8c7a7eSZhanjun Dong 	void *null_header;
442*9c8c7a7eSZhanjun Dong 
443*9c8c7a7eSZhanjun Dong 	if (gc->ads_null_cache) {
444*9c8c7a7eSZhanjun Dong 		*outptr = gc->ads_null_cache;
445*9c8c7a7eSZhanjun Dong 		*size = tmp;
446*9c8c7a7eSZhanjun Dong 		return 0;
447*9c8c7a7eSZhanjun Dong 	}
448*9c8c7a7eSZhanjun Dong 
449*9c8c7a7eSZhanjun Dong 	null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL);
450*9c8c7a7eSZhanjun Dong 	if (!null_header)
451*9c8c7a7eSZhanjun Dong 		return -ENOMEM;
452*9c8c7a7eSZhanjun Dong 
453*9c8c7a7eSZhanjun Dong 	gc->ads_null_cache = null_header;
454*9c8c7a7eSZhanjun Dong 	*outptr = null_header;
455*9c8c7a7eSZhanjun Dong 	*size = tmp;
456*9c8c7a7eSZhanjun Dong 
457*9c8c7a7eSZhanjun Dong 	return 0;
458*9c8c7a7eSZhanjun Dong }
459*9c8c7a7eSZhanjun Dong 
460*9c8c7a7eSZhanjun Dong /**
461*9c8c7a7eSZhanjun Dong  * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture
462*9c8c7a7eSZhanjun Dong  * @guc: point to xe_guc structure
463*9c8c7a7eSZhanjun Dong  *
464*9c8c7a7eSZhanjun Dong  * Calculate the worst size for GuC register capture by including all possible engines classes.
465*9c8c7a7eSZhanjun Dong  *
466*9c8c7a7eSZhanjun Dong  * Returns: Calculated size
467*9c8c7a7eSZhanjun Dong  */
468*9c8c7a7eSZhanjun Dong size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
469*9c8c7a7eSZhanjun Dong {
470*9c8c7a7eSZhanjun Dong 	size_t total_size, class_size, instance_size, global_size;
471*9c8c7a7eSZhanjun Dong 	int i, j;
472*9c8c7a7eSZhanjun Dong 
473*9c8c7a7eSZhanjun Dong 	/*
474*9c8c7a7eSZhanjun Dong 	 * This function calculates the worst case register lists size by
475*9c8c7a7eSZhanjun Dong 	 * including all possible engines classes. It is called during the
476*9c8c7a7eSZhanjun Dong 	 * first of a two-phase GuC (and ADS-population) initialization
477*9c8c7a7eSZhanjun Dong 	 * sequence, that is, during the pre-hwconfig phase before we have
478*9c8c7a7eSZhanjun Dong 	 * the exact engine fusing info.
479*9c8c7a7eSZhanjun Dong 	 */
480*9c8c7a7eSZhanjun Dong 	total_size = PAGE_SIZE;	/* Pad a page in front for empty lists */
481*9c8c7a7eSZhanjun Dong 	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
482*9c8c7a7eSZhanjun Dong 		for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) {
483*9c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
484*9c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
485*9c8c7a7eSZhanjun Dong 						       j, &class_size) < 0)
486*9c8c7a7eSZhanjun Dong 				class_size = 0;
487*9c8c7a7eSZhanjun Dong 			if (xe_guc_capture_getlistsize(guc, i,
488*9c8c7a7eSZhanjun Dong 						       GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
489*9c8c7a7eSZhanjun Dong 						       j, &instance_size) < 0)
490*9c8c7a7eSZhanjun Dong 				instance_size = 0;
491*9c8c7a7eSZhanjun Dong 			total_size += class_size + instance_size;
492*9c8c7a7eSZhanjun Dong 		}
493*9c8c7a7eSZhanjun Dong 		if (xe_guc_capture_getlistsize(guc, i,
494*9c8c7a7eSZhanjun Dong 					       GUC_STATE_CAPTURE_TYPE_GLOBAL,
495*9c8c7a7eSZhanjun Dong 					       0, &global_size) < 0)
496*9c8c7a7eSZhanjun Dong 			global_size = 0;
497*9c8c7a7eSZhanjun Dong 		total_size += global_size;
498*9c8c7a7eSZhanjun Dong 	}
499*9c8c7a7eSZhanjun Dong 
500*9c8c7a7eSZhanjun Dong 	return PAGE_ALIGN(total_size);
501*9c8c7a7eSZhanjun Dong }
502*9c8c7a7eSZhanjun Dong 
503*9c8c7a7eSZhanjun Dong /**
504*9c8c7a7eSZhanjun Dong  * xe_guc_capture_init - Init for GuC register capture
505*9c8c7a7eSZhanjun Dong  * @guc: The GuC object
506*9c8c7a7eSZhanjun Dong  *
507*9c8c7a7eSZhanjun Dong  * Init for GuC register capture, alloc memory for capture data structure.
508*9c8c7a7eSZhanjun Dong  *
509*9c8c7a7eSZhanjun Dong  * Returns: 0 if success.
510*9c8c7a7eSZhanjun Dong 	    -ENOMEM if out of memory
511*9c8c7a7eSZhanjun Dong  */
512*9c8c7a7eSZhanjun Dong int xe_guc_capture_init(struct xe_guc *guc)
513*9c8c7a7eSZhanjun Dong {
514*9c8c7a7eSZhanjun Dong 	guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL);
515*9c8c7a7eSZhanjun Dong 	if (!guc->capture)
516*9c8c7a7eSZhanjun Dong 		return -ENOMEM;
517*9c8c7a7eSZhanjun Dong 
518*9c8c7a7eSZhanjun Dong 	guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc));
519*9c8c7a7eSZhanjun Dong 	return 0;
520*9c8c7a7eSZhanjun Dong }
521