1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2021-2024 Intel Corporation
4 */
5
6 #include <linux/types.h>
7
8 #include <drm/drm_managed.h>
9 #include <drm/drm_print.h>
10
11 #include "abi/guc_actions_abi.h"
12 #include "abi/guc_capture_abi.h"
13 #include "abi/guc_log_abi.h"
14 #include "regs/xe_engine_regs.h"
15 #include "regs/xe_gt_regs.h"
16
17 #include "xe_bo_types.h"
18 #include "xe_device.h"
19 #include "xe_exec_queue_types.h"
20 #include "xe_gt.h"
21 #include "xe_gt_mcr.h"
22 #include "xe_gt_printk.h"
23 #include "xe_guc.h"
24 #include "xe_guc_capture.h"
25 #include "xe_guc_capture_types.h"
26 #include "xe_guc_ct.h"
27 #include "xe_guc_exec_queue_types.h"
28 #include "xe_guc_log.h"
29 #include "xe_guc_submit_types.h"
30 #include "xe_guc_submit.h"
31 #include "xe_hw_engine_types.h"
32 #include "xe_hw_engine.h"
33 #include "xe_lrc.h"
34 #include "xe_macros.h"
35 #include "xe_map.h"
36 #include "xe_mmio.h"
37 #include "xe_sched_job.h"
38
39 /*
40 * struct __guc_capture_bufstate
41 *
42 * Book-keeping structure used to track read and write pointers
43 * as we extract error capture data from the GuC-log-buffer's
44 * error-capture region as a stream of dwords.
45 */
46 struct __guc_capture_bufstate {
47 u32 size;
48 u32 data_offset;
49 u32 rd;
50 u32 wr;
51 };
52
53 /*
54 * struct __guc_capture_parsed_output - extracted error capture node
55 *
56 * A single unit of extracted error-capture output data grouped together
57 * at an engine-instance level. We keep these nodes in a linked list.
58 * See cachelist and outlist below.
59 */
60 struct __guc_capture_parsed_output {
61 /*
62 * A single set of 3 capture lists: a global-list
63 * an engine-class-list and an engine-instance list.
64 * outlist in __guc_capture_parsed_output will keep
65 * a linked list of these nodes that will eventually
66 * be detached from outlist and attached into to
67 * xe_codedump in response to a context reset
68 */
69 struct list_head link;
70 bool is_partial;
71 u32 eng_class;
72 u32 eng_inst;
73 u32 guc_id;
74 u32 lrca;
75 u32 type;
76 bool locked;
77 enum xe_hw_engine_snapshot_source_id source;
78 struct gcap_reg_list_info {
79 u32 vfid;
80 u32 num_regs;
81 struct guc_mmio_reg *regs;
82 } reginfo[GUC_STATE_CAPTURE_TYPE_MAX];
83 #define GCAP_PARSED_REGLIST_INDEX_GLOBAL BIT(GUC_STATE_CAPTURE_TYPE_GLOBAL)
84 #define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS)
85 };
86
87 /*
88 * Define all device tables of GuC error capture register lists
89 * NOTE:
90 * For engine-registers, GuC only needs the register offsets
91 * from the engine-mmio-base
92 *
93 * 64 bit registers need 2 entries for low 32 bit register and high 32 bit
94 * register, for example:
95 * Register data_type flags mask Register name
96 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
97 * { XXX_REG_HI(0), REG_64BIT_HI_DW,, 0, 0, "XXX_REG"},
98 * 1. data_type: Indicate is hi/low 32 bit for a 64 bit register
99 * A 64 bit register define requires 2 consecutive entries,
100 * with low dword first and hi dword the second.
101 * 2. Register name: null for incompleted define
102 * 3. Incorrect order will trigger XE_WARN.
103 */
104 #define COMMON_XELP_BASE_GLOBAL \
105 { FORCEWAKE_GT, REG_32BIT, 0, 0, 0, "FORCEWAKE_GT"}
106
107 #define COMMON_BASE_ENGINE_INSTANCE \
108 { RING_HWSTAM(0), REG_32BIT, 0, 0, 0, "HWSTAM"}, \
109 { RING_HWS_PGA(0), REG_32BIT, 0, 0, 0, "RING_HWS_PGA"}, \
110 { RING_HEAD(0), REG_32BIT, 0, 0, 0, "RING_HEAD"}, \
111 { RING_TAIL(0), REG_32BIT, 0, 0, 0, "RING_TAIL"}, \
112 { RING_CTL(0), REG_32BIT, 0, 0, 0, "RING_CTL"}, \
113 { RING_MI_MODE(0), REG_32BIT, 0, 0, 0, "RING_MI_MODE"}, \
114 { GFX_MODE(0), REG_32BIT, 0, 0, 0, "GFX_MODE"}, \
115 { RING_ESR(0), REG_32BIT, 0, 0, 0, "RING_ESR"}, \
116 { RING_EMR(0), REG_32BIT, 0, 0, 0, "RING_EMR"}, \
117 { RING_EIR(0), REG_32BIT, 0, 0, 0, "RING_EIR"}, \
118 { RING_IMR(0), REG_32BIT, 0, 0, 0, "RING_IMR"}, \
119 { RING_IPEHR(0), REG_32BIT, 0, 0, 0, "IPEHR"}, \
120 { RING_INSTDONE(0), REG_32BIT, 0, 0, 0, "RING_INSTDONE"}, \
121 { INDIRECT_RING_STATE(0), REG_32BIT, 0, 0, 0, "INDIRECT_RING_STATE"}, \
122 { RING_CURRENT_LRCA(0), REG_32BIT, 0, 0, 0, "CURRENT_LRCA"}, \
123 { RING_ACTHD(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
124 { RING_ACTHD_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "ACTHD"}, \
125 { RING_BBADDR(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
126 { RING_BBADDR_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_BBADDR"}, \
127 { RING_START(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
128 { RING_START_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_START"}, \
129 { RING_DMA_FADD(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
130 { RING_DMA_FADD_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_DMA_FADD"}, \
131 { RING_EXECLIST_STATUS_LO(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
132 { RING_EXECLIST_STATUS_HI(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_EXECLIST_STATUS"}, \
133 { RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
134 { RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_EXECLIST_SQ_CONTENTS"}
135
136 #define COMMON_XELP_RC_CLASS \
137 { RCU_MODE, REG_32BIT, 0, 0, 0, "RCU_MODE"}
138
139 #define COMMON_XELP_RC_CLASS_INSTDONE \
140 { SC_INSTDONE, REG_32BIT, 0, 0, 0, "SC_INSTDONE"}, \
141 { SC_INSTDONE_EXTRA, REG_32BIT, 0, 0, 0, "SC_INSTDONE_EXTRA"}, \
142 { SC_INSTDONE_EXTRA2, REG_32BIT, 0, 0, 0, "SC_INSTDONE_EXTRA2"}
143
144 #define XELP_VEC_CLASS_REGS \
145 { SFC_DONE(0), 0, 0, 0, 0, "SFC_DONE[0]"}, \
146 { SFC_DONE(1), 0, 0, 0, 0, "SFC_DONE[1]"}, \
147 { SFC_DONE(2), 0, 0, 0, 0, "SFC_DONE[2]"}, \
148 { SFC_DONE(3), 0, 0, 0, 0, "SFC_DONE[3]"}
149
150 #define XE3P_BASE_ENGINE_INSTANCE \
151 { RING_CSMQDEBUG(0), REG_32BIT, 0, 0, 0, "CSMQDEBUG"}
152
153 /* XE_LP Global */
154 static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
155 COMMON_XELP_BASE_GLOBAL,
156 };
157
158 /* Render / Compute Per-Engine-Instance */
159 static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = {
160 COMMON_BASE_ENGINE_INSTANCE,
161 };
162
163 /* Render / Compute Engine-Class */
164 static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = {
165 COMMON_XELP_RC_CLASS,
166 COMMON_XELP_RC_CLASS_INSTDONE,
167 };
168
169 /* Render / Compute Engine-Class for xehpg */
170 static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = {
171 COMMON_XELP_RC_CLASS,
172 };
173
174 /* Media Decode/Encode Per-Engine-Instance */
175 static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = {
176 COMMON_BASE_ENGINE_INSTANCE,
177 };
178
179 /* Video Enhancement Engine-Class */
180 static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = {
181 XELP_VEC_CLASS_REGS,
182 };
183
184 /* Video Enhancement Per-Engine-Instance */
185 static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = {
186 COMMON_BASE_ENGINE_INSTANCE,
187 };
188
189 /* Blitter Per-Engine-Instance */
190 static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = {
191 COMMON_BASE_ENGINE_INSTANCE,
192 };
193
194 /* XE_LP - GSC Per-Engine-Instance */
195 static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {
196 COMMON_BASE_ENGINE_INSTANCE,
197 };
198
199 /* Render / Compute Per-Engine-Instance */
200 static const struct __guc_mmio_reg_descr xe3p_rc_inst_regs[] = {
201 COMMON_BASE_ENGINE_INSTANCE,
202 XE3P_BASE_ENGINE_INSTANCE,
203 };
204
205 /*
206 * Empty list to prevent warnings about unknown class/instance types
207 * as not all class/instance types have entries on all platforms.
208 */
209 static const struct __guc_mmio_reg_descr empty_regs_list[] = {
210 };
211
212 #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
213 #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x)
214 #define MAKE_REGLIST(regslist, regsowner, regstype, class) \
215 { \
216 regslist, \
217 ARRAY_SIZE(regslist), \
218 TO_GCAP_DEF_OWNER(regsowner), \
219 TO_GCAP_DEF_TYPE(regstype), \
220 class \
221 }
222
223 /* List of lists for legacy graphic product version < 1255 */
224 static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {
225 MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
226 MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
227 MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
228 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
229 MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
230 MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
231 MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
232 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
233 MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
234 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
235 MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
236 {}
237 };
238
239 /* List of lists for graphic product version >= 1255 */
240 static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = {
241 MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
242 MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
243 MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
244 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
245 MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
246 MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
247 MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
248 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
249 MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
250 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
251 MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
252 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_PAGING),
253 MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_PAGING),
254 {}
255 };
256
257 /* List of lists for Xe3p and beyond */
258 static const struct __guc_mmio_reg_descr_group xe3p_lists[] = {
259 MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
260 MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
261 MAKE_REGLIST(xe3p_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
262 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
263 MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
264 MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
265 MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
266 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
267 MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
268 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
269 MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
270 MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_PAGING),
271 MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_PAGING),
272 {}
273 };
274 static const char * const capture_list_type_names[] = {
275 "Global",
276 "Class",
277 "Instance",
278 };
279
280 static const char * const capture_engine_class_names[] = {
281 "Render/Compute",
282 "Video",
283 "VideoEnhance",
284 "Blitter",
285 "GSC-Other",
286 "Paging",
287 };
288
289 struct __guc_capture_ads_cache {
290 bool is_valid;
291 void *ptr;
292 size_t size;
293 int status;
294 };
295
296 struct xe_guc_state_capture {
297 const struct __guc_mmio_reg_descr_group *reglists;
298 /**
299 * NOTE: steered registers have multiple instances depending on the HW configuration
300 * (slices or dual-sub-slices) and thus depends on HW fuses discovered
301 */
302 struct __guc_mmio_reg_descr_group *extlists;
303 struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
304 [GUC_STATE_CAPTURE_TYPE_MAX]
305 [GUC_CAPTURE_LIST_CLASS_MAX];
306 void *ads_null_cache;
307 struct list_head cachelist;
308 #define PREALLOC_NODES_MAX_COUNT (3 * GUC_MAX_ENGINE_CLASSES * GUC_MAX_INSTANCES_PER_CLASS)
309 #define PREALLOC_NODES_DEFAULT_NUMREGS 64
310
311 int max_mmio_per_node;
312 struct list_head outlist;
313 };
314
315 static void
316 guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture *gc,
317 struct __guc_capture_parsed_output *node);
318
319 static const struct __guc_mmio_reg_descr_group *
guc_capture_get_device_reglist(struct xe_device * xe)320 guc_capture_get_device_reglist(struct xe_device *xe)
321 {
322 if (GRAPHICS_VER(xe) >= 35)
323 return xe3p_lists;
324 else if (GRAPHICS_VERx100(xe) >= 1255)
325 return xe_hpg_lists;
326 else
327 return xe_lp_lists;
328 }
329
330 static const struct __guc_mmio_reg_descr_group *
guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group * reglists,u32 owner,u32 type,enum guc_capture_list_class_type capture_class)331 guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
332 u32 owner, u32 type, enum guc_capture_list_class_type capture_class)
333 {
334 int i;
335
336 if (!reglists)
337 return NULL;
338
339 for (i = 0; reglists[i].list; ++i) {
340 if (reglists[i].owner == owner && reglists[i].type == type &&
341 (reglists[i].engine == capture_class ||
342 reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL))
343 return ®lists[i];
344 }
345
346 return NULL;
347 }
348
349 const struct __guc_mmio_reg_descr_group *
xe_guc_capture_get_reg_desc_list(struct xe_gt * gt,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,bool is_ext)350 xe_guc_capture_get_reg_desc_list(struct xe_gt *gt, u32 owner, u32 type,
351 enum guc_capture_list_class_type capture_class, bool is_ext)
352 {
353 const struct __guc_mmio_reg_descr_group *reglists;
354
355 if (is_ext) {
356 struct xe_guc *guc = >->uc.guc;
357
358 reglists = guc->capture->extlists;
359 } else {
360 reglists = guc_capture_get_device_reglist(gt_to_xe(gt));
361 }
362 return guc_capture_get_one_list(reglists, owner, type, capture_class);
363 }
364
365 struct __ext_steer_reg {
366 const char *name;
367 struct xe_reg_mcr reg;
368 };
369
370 static const struct __ext_steer_reg xe_extregs[] = {
371 {"SAMPLER_INSTDONE", SAMPLER_INSTDONE},
372 {"ROW_INSTDONE", ROW_INSTDONE}
373 };
374
375 static const struct __ext_steer_reg xehpg_extregs[] = {
376 {"SC_INSTDONE", XEHPG_SC_INSTDONE},
377 {"SC_INSTDONE_EXTRA", XEHPG_SC_INSTDONE_EXTRA},
378 {"SC_INSTDONE_EXTRA2", XEHPG_SC_INSTDONE_EXTRA2},
379 {"INSTDONE_GEOM_SVGUNIT", XEHPG_INSTDONE_GEOM_SVGUNIT}
380 };
381
__fill_ext_reg(struct __guc_mmio_reg_descr * ext,const struct __ext_steer_reg * extlist,u32 dss_id,u16 slice_id,u16 subslice_id)382 static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
383 const struct __ext_steer_reg *extlist,
384 u32 dss_id, u16 slice_id, u16 subslice_id)
385 {
386 if (!ext || !extlist)
387 return;
388
389 ext->reg = XE_REG(extlist->reg.__reg.addr);
390 ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1);
391 ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
392 ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
393 ext->dss_id = dss_id;
394 ext->regname = extlist->name;
395 }
396
397 static int
__alloc_ext_regs(struct drm_device * drm,struct __guc_mmio_reg_descr_group * newlist,const struct __guc_mmio_reg_descr_group * rootlist,int num_regs)398 __alloc_ext_regs(struct drm_device *drm, struct __guc_mmio_reg_descr_group *newlist,
399 const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)
400 {
401 struct __guc_mmio_reg_descr *list;
402
403 list = drmm_kzalloc(drm, num_regs * sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
404 if (!list)
405 return -ENOMEM;
406
407 newlist->list = list;
408 newlist->num_regs = num_regs;
409 newlist->owner = rootlist->owner;
410 newlist->engine = rootlist->engine;
411 newlist->type = rootlist->type;
412
413 return 0;
414 }
415
guc_capture_get_steer_reg_num(struct xe_device * xe)416 static int guc_capture_get_steer_reg_num(struct xe_device *xe)
417 {
418 int num = ARRAY_SIZE(xe_extregs);
419
420 if (GRAPHICS_VERx100(xe) >= 1255)
421 num += ARRAY_SIZE(xehpg_extregs);
422
423 return num;
424 }
425
guc_capture_alloc_steered_lists(struct xe_guc * guc)426 static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
427 {
428 struct xe_gt *gt = guc_to_gt(guc);
429 u16 slice, subslice;
430 int dss, i, total = 0;
431 const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists;
432 const struct __guc_mmio_reg_descr_group *list;
433 struct __guc_mmio_reg_descr_group *extlists;
434 struct __guc_mmio_reg_descr *extarray;
435 bool has_xehpg_extregs = GRAPHICS_VERx100(gt_to_xe(gt)) >= 1255;
436 struct drm_device *drm = >_to_xe(gt)->drm;
437 bool has_rcs_ccs = false;
438 struct xe_hw_engine *hwe;
439 enum xe_hw_engine_id id;
440
441 /*
442 * If GT has no rcs/ccs, no need to alloc steered list.
443 * Currently, only rcs/ccs has steering register, if in the future,
444 * other engine types has steering register, this condition check need
445 * to be extended
446 */
447 for_each_hw_engine(hwe, gt, id) {
448 if (xe_hwe_to_guc_capture_class(hwe) ==
449 GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
450 has_rcs_ccs = true;
451 break;
452 }
453 }
454
455 if (!has_rcs_ccs)
456 return;
457
458 /* steered registers currently only exist for the render-class */
459 list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
460 GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
461 GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE);
462 /*
463 * Skip if this platform has no engine class registers or if extlists
464 * was previously allocated
465 */
466 if (!list || guc->capture->extlists)
467 return;
468
469 {
470 xe_dss_mask_t all_dss;
471
472 total = bitmap_weighted_or(all_dss, gt->fuse_topo.g_dss_mask,
473 gt->fuse_topo.c_dss_mask,
474 XE_MAX_DSS_FUSE_BITS) *
475 guc_capture_get_steer_reg_num(guc_to_xe(guc));
476 }
477
478 if (!total)
479 return;
480
481 /* allocate an extra for an end marker */
482 extlists = drmm_kzalloc(drm, 2 * sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL);
483 if (!extlists)
484 return;
485
486 if (__alloc_ext_regs(drm, &extlists[0], list, total)) {
487 drmm_kfree(drm, extlists);
488 return;
489 }
490
491 /* For steering registers, the list is generated at run-time */
492 extarray = (struct __guc_mmio_reg_descr *)extlists[0].list;
493 for_each_dss_steering(dss, gt, slice, subslice) {
494 for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) {
495 __fill_ext_reg(extarray, &xe_extregs[i], dss, slice, subslice);
496 ++extarray;
497 }
498
499 if (has_xehpg_extregs)
500 for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {
501 __fill_ext_reg(extarray, &xehpg_extregs[i], dss, slice, subslice);
502 ++extarray;
503 }
504 }
505
506 extlists[0].num_regs = total;
507
508 xe_gt_dbg(guc_to_gt(guc), "capture found %d ext-regs.\n", total);
509 guc->capture->extlists = extlists;
510 }
511
512 static int
guc_capture_list_init(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,struct guc_mmio_reg * ptr,u16 num_entries)513 guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
514 enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr,
515 u16 num_entries)
516 {
517 u32 ptr_idx = 0, list_idx = 0;
518 const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
519 struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;
520 const struct __guc_mmio_reg_descr_group *match;
521 u32 list_num;
522
523 if (!reglists)
524 return -ENODEV;
525
526 match = guc_capture_get_one_list(reglists, owner, type, capture_class);
527 if (!match)
528 return -ENODATA;
529
530 list_num = match->num_regs;
531 for (list_idx = 0; ptr_idx < num_entries && list_idx < list_num; ++list_idx, ++ptr_idx) {
532 ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
533 ptr[ptr_idx].value = 0xDEADF00D;
534 ptr[ptr_idx].flags = match->list[list_idx].flags;
535 ptr[ptr_idx].mask = match->list[list_idx].mask;
536 }
537
538 match = guc_capture_get_one_list(extlists, owner, type, capture_class);
539 if (match)
540 for (ptr_idx = list_num, list_idx = 0;
541 ptr_idx < num_entries && list_idx < match->num_regs;
542 ++ptr_idx, ++list_idx) {
543 ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
544 ptr[ptr_idx].value = 0xDEADF00D;
545 ptr[ptr_idx].flags = match->list[list_idx].flags;
546 ptr[ptr_idx].mask = match->list[list_idx].mask;
547 }
548
549 if (ptr_idx < num_entries)
550 xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out-of %d.\n",
551 ptr_idx, num_entries);
552
553 return 0;
554 }
555
556 static int
guc_cap_list_num_regs(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class)557 guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
558 enum guc_capture_list_class_type capture_class)
559 {
560 const struct __guc_mmio_reg_descr_group *match;
561 int num_regs = 0;
562
563 match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class);
564 if (match)
565 num_regs = match->num_regs;
566
567 match = guc_capture_get_one_list(guc->capture->extlists, owner, type, capture_class);
568 if (match)
569 num_regs += match->num_regs;
570 else
571 /*
572 * If a caller wants the full register dump size but we have
573 * not yet got the hw-config, which is before max_mmio_per_node
574 * is initialized, then provide a worst-case number for
575 * extlists based on max dss fuse bits, but only ever for
576 * render/compute
577 */
578 if (owner == GUC_CAPTURE_LIST_INDEX_PF &&
579 type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
580 capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE &&
581 !guc->capture->max_mmio_per_node)
582 num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) *
583 XE_MAX_DSS_FUSE_BITS;
584
585 return num_regs;
586 }
587
588 static int
guc_capture_getlistsize(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,size_t * size,bool is_purpose_est)589 guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
590 enum guc_capture_list_class_type capture_class,
591 size_t *size, bool is_purpose_est)
592 {
593 struct xe_guc_state_capture *gc = guc->capture;
594 struct xe_gt *gt = guc_to_gt(guc);
595 struct __guc_capture_ads_cache *cache;
596 int num_regs;
597
598 xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX);
599 xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX);
600
601 cache = &gc->ads_cache[owner][type][capture_class];
602 if (!gc->reglists) {
603 xe_gt_warn(gt, "No capture reglist for this device\n");
604 return -ENODEV;
605 }
606
607 if (cache->is_valid) {
608 *size = cache->size;
609 return cache->status;
610 }
611
612 if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
613 !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) {
614 if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL)
615 xe_gt_warn(gt, "Missing capture reglist: global!\n");
616 else
617 xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n",
618 capture_list_type_names[type], type,
619 capture_engine_class_names[capture_class], capture_class);
620 return -ENODEV;
621 }
622
623 num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
624 /* intentional empty lists can exist depending on hw config */
625 if (!num_regs)
626 return -ENODATA;
627
628 if (size)
629 *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
630 (num_regs * sizeof(struct guc_mmio_reg)));
631
632 return 0;
633 }
634
635 /**
636 * xe_guc_capture_getlistsize - Get list size for owner/type/class combination
637 * @guc: The GuC object
638 * @owner: PF/VF owner
639 * @type: GuC capture register type
640 * @capture_class: GuC capture engine class id
641 * @size: Point to the size
642 *
643 * This function will get the list for the owner/type/class combination, and
644 * return the page aligned list size.
645 *
646 * Returns: 0 on success or a negative error code on failure.
647 */
648 int
xe_guc_capture_getlistsize(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,size_t * size)649 xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
650 enum guc_capture_list_class_type capture_class, size_t *size)
651 {
652 return guc_capture_getlistsize(guc, owner, type, capture_class, size, false);
653 }
654
655 /**
656 * xe_guc_capture_getlist - Get register capture list for owner/type/class
657 * combination
658 * @guc: The GuC object
659 * @owner: PF/VF owner
660 * @type: GuC capture register type
661 * @capture_class: GuC capture engine class id
662 * @outptr: Point to cached register capture list
663 *
664 * This function will get the register capture list for the owner/type/class
665 * combination.
666 *
667 * Returns: 0 on success or a negative error code on failure.
668 */
669 int
xe_guc_capture_getlist(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,void ** outptr)670 xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type,
671 enum guc_capture_list_class_type capture_class, void **outptr)
672 {
673 struct xe_guc_state_capture *gc = guc->capture;
674 struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class];
675 struct guc_debug_capture_list *listnode;
676 int ret, num_regs;
677 u8 *caplist, *tmp;
678 size_t size = 0;
679
680 if (!gc->reglists)
681 return -ENODEV;
682
683 if (cache->is_valid) {
684 *outptr = cache->ptr;
685 return cache->status;
686 }
687
688 ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size);
689 if (ret) {
690 cache->is_valid = true;
691 cache->ptr = NULL;
692 cache->size = 0;
693 cache->status = ret;
694 return ret;
695 }
696
697 caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL);
698 if (!caplist)
699 return -ENOMEM;
700
701 /* populate capture list header */
702 tmp = caplist;
703 num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
704 listnode = (struct guc_debug_capture_list *)tmp;
705 listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
706
707 /* populate list of register descriptor */
708 tmp += sizeof(struct guc_debug_capture_list);
709 guc_capture_list_init(guc, owner, type, capture_class,
710 (struct guc_mmio_reg *)tmp, num_regs);
711
712 /* cache this list */
713 cache->is_valid = true;
714 cache->ptr = caplist;
715 cache->size = size;
716 cache->status = 0;
717
718 *outptr = caplist;
719
720 return 0;
721 }
722
723 /**
724 * xe_guc_capture_getnullheader - Get a null list for register capture
725 * @guc: The GuC object
726 * @outptr: Point to cached register capture list
727 * @size: Point to the size
728 *
729 * This function will alloc for a null list for register capture.
730 *
731 * Returns: 0 on success or a negative error code on failure.
732 */
733 int
xe_guc_capture_getnullheader(struct xe_guc * guc,void ** outptr,size_t * size)734 xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size)
735 {
736 struct xe_guc_state_capture *gc = guc->capture;
737 int tmp = sizeof(u32) * 4;
738 void *null_header;
739
740 if (gc->ads_null_cache) {
741 *outptr = gc->ads_null_cache;
742 *size = tmp;
743 return 0;
744 }
745
746 null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL);
747 if (!null_header)
748 return -ENOMEM;
749
750 gc->ads_null_cache = null_header;
751 *outptr = null_header;
752 *size = tmp;
753
754 return 0;
755 }
756
757 /**
758 * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture
759 * @guc: point to xe_guc structure
760 *
761 * Calculate the worst size for GuC register capture by including all possible engines classes.
762 *
763 * Returns: Calculated size
764 */
xe_guc_capture_ads_input_worst_size(struct xe_guc * guc)765 size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
766 {
767 size_t total_size, class_size, instance_size, global_size;
768 int i, j;
769
770 /*
771 * This function calculates the worst case register lists size by
772 * including all possible engines classes. It is called during the
773 * first of a two-phase GuC (and ADS-population) initialization
774 * sequence, that is, during the pre-hwconfig phase before we have
775 * the exact engine fusing info.
776 */
777 total_size = PAGE_SIZE; /* Pad a page in front for empty lists */
778 for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
779 for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) {
780 if (!xe_guc_has_paging_engine(guc) &&
781 j == GUC_CAPTURE_LIST_CLASS_PAGING)
782 continue;
783
784 if (xe_guc_capture_getlistsize(guc, i,
785 GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
786 j, &class_size) < 0)
787 class_size = 0;
788 if (xe_guc_capture_getlistsize(guc, i,
789 GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
790 j, &instance_size) < 0)
791 instance_size = 0;
792 total_size += class_size + instance_size;
793 }
794 if (xe_guc_capture_getlistsize(guc, i,
795 GUC_STATE_CAPTURE_TYPE_GLOBAL,
796 0, &global_size) < 0)
797 global_size = 0;
798 total_size += global_size;
799 }
800
801 return PAGE_ALIGN(total_size);
802 }
803
guc_capture_output_size_est(struct xe_guc * guc)804 static int guc_capture_output_size_est(struct xe_guc *guc)
805 {
806 struct xe_gt *gt = guc_to_gt(guc);
807 struct xe_hw_engine *hwe;
808 enum xe_hw_engine_id id;
809
810 int capture_size = 0;
811 size_t tmp = 0;
812
813 if (!guc->capture)
814 return -ENODEV;
815
816 /*
817 * If every single engine-instance suffered a failure in quick succession but
818 * were all unrelated, then a burst of multiple error-capture events would dump
819 * registers for every one engine instance, one at a time. In this case, GuC
820 * would even dump the global-registers repeatedly.
821 *
822 * For each engine instance, there would be 1 x guc_state_capture_group_t output
823 * followed by 3 x guc_state_capture_t lists. The latter is how the register
824 * dumps are split across different register types (where the '3' are global vs class
825 * vs instance).
826 */
827 for_each_hw_engine(hwe, gt, id) {
828 enum guc_capture_list_class_type capture_class;
829
830 capture_class = xe_hwe_to_guc_capture_class(hwe);
831 capture_size += sizeof(struct guc_state_capture_group_header_t) +
832 (3 * sizeof(struct guc_state_capture_header_t));
833
834 if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_GLOBAL,
835 0, &tmp, true))
836 capture_size += tmp;
837 if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
838 capture_class, &tmp, true))
839 capture_size += tmp;
840 if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
841 capture_class, &tmp, true))
842 capture_size += tmp;
843 }
844
845 return capture_size;
846 }
847
848 /*
849 * Add on a 3x multiplier to allow for multiple back-to-back captures occurring
850 * before the Xe can read the data out and process it
851 */
852 #define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
853
check_guc_capture_size(struct xe_guc * guc)854 static void check_guc_capture_size(struct xe_guc *guc)
855 {
856 int capture_size = guc_capture_output_size_est(guc);
857 int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
858 u32 buffer_size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE;
859
860 /*
861 * NOTE: capture_size is much smaller than the capture region
862 * allocation (DG2: <80K vs 1MB).
863 * Additionally, its based on space needed to fit all engines getting
864 * reset at once within the same G2H handler task slot. This is very
865 * unlikely. However, if GuC really does run out of space for whatever
866 * reason, we will see an separate warning message when processing the
867 * G2H event capture-notification, search for:
868 * xe_guc_STATE_CAPTURE_EVENT_STATUS_NOSPACE.
869 */
870 if (capture_size < 0)
871 xe_gt_dbg(guc_to_gt(guc),
872 "Failed to calculate error state capture buffer minimum size: %d!\n",
873 capture_size);
874 if (capture_size > buffer_size)
875 xe_gt_dbg(guc_to_gt(guc), "Error state capture buffer maybe small: %d < %d\n",
876 buffer_size, capture_size);
877 else if (spare_size > buffer_size)
878 xe_gt_dbg(guc_to_gt(guc),
879 "Error state capture buffer lacks spare size: %d < %d (min = %d)\n",
880 buffer_size, spare_size, capture_size);
881 }
882
883 static void
guc_capture_add_node_to_list(struct __guc_capture_parsed_output * node,struct list_head * list)884 guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node,
885 struct list_head *list)
886 {
887 list_add(&node->link, list);
888 }
889
890 static void
guc_capture_add_node_to_outlist(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)891 guc_capture_add_node_to_outlist(struct xe_guc_state_capture *gc,
892 struct __guc_capture_parsed_output *node)
893 {
894 guc_capture_remove_stale_matches_from_list(gc, node);
895 guc_capture_add_node_to_list(node, &gc->outlist);
896 }
897
898 static void
guc_capture_add_node_to_cachelist(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)899 guc_capture_add_node_to_cachelist(struct xe_guc_state_capture *gc,
900 struct __guc_capture_parsed_output *node)
901 {
902 guc_capture_add_node_to_list(node, &gc->cachelist);
903 }
904
905 static void
guc_capture_free_outlist_node(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * n)906 guc_capture_free_outlist_node(struct xe_guc_state_capture *gc,
907 struct __guc_capture_parsed_output *n)
908 {
909 if (n) {
910 n->locked = 0;
911 list_del(&n->link);
912 /* put node back to cache list */
913 guc_capture_add_node_to_cachelist(gc, n);
914 }
915 }
916
917 static void
guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)918 guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture *gc,
919 struct __guc_capture_parsed_output *node)
920 {
921 struct __guc_capture_parsed_output *n, *ntmp;
922 int guc_id = node->guc_id;
923
924 list_for_each_entry_safe(n, ntmp, &gc->outlist, link) {
925 if (n != node && !n->locked && n->guc_id == guc_id)
926 guc_capture_free_outlist_node(gc, n);
927 }
928 }
929
930 static void
guc_capture_init_node(struct xe_guc * guc,struct __guc_capture_parsed_output * node)931 guc_capture_init_node(struct xe_guc *guc, struct __guc_capture_parsed_output *node)
932 {
933 struct guc_mmio_reg *tmp[GUC_STATE_CAPTURE_TYPE_MAX];
934 int i;
935
936 for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
937 tmp[i] = node->reginfo[i].regs;
938 memset(tmp[i], 0, sizeof(struct guc_mmio_reg) *
939 guc->capture->max_mmio_per_node);
940 }
941 memset(node, 0, sizeof(*node));
942 for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i)
943 node->reginfo[i].regs = tmp[i];
944
945 INIT_LIST_HEAD(&node->link);
946 }
947
948 /**
949 * DOC: Init, G2H-event and reporting flows for GuC-error-capture
950 *
951 * KMD Init time flows:
952 * --------------------
953 * --> alloc A: GuC input capture regs lists (registered to GuC via ADS).
954 * xe_guc_ads acquires the register lists by calling
955 * xe_guc_capture_getlistsize and xe_guc_capture_getlist 'n' times,
956 * where n = 1 for global-reg-list +
957 * num_engine_classes for class-reg-list +
958 * num_engine_classes for instance-reg-list
959 * (since all instances of the same engine-class type
960 * have an identical engine-instance register-list).
961 * ADS module also calls separately for PF vs VF.
962 *
963 * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))
964 * Size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE (warns if on too-small)
965 * Note2: 'x 3' to hold multiple capture groups
966 *
967 * GUC Runtime notify capture:
968 * --------------------------
969 * --> G2H STATE_CAPTURE_NOTIFICATION
970 * L--> xe_guc_capture_process
971 * L--> Loop through B (head..tail) and for each engine instance's
972 * err-state-captured register-list we find, we alloc 'C':
973 * --> alloc C: A capture-output-node structure that includes misc capture info along
974 * with 3 register list dumps (global, engine-class and engine-instance)
975 * This node is created from a pre-allocated list of blank nodes in
976 * guc->capture->cachelist and populated with the error-capture
977 * data from GuC and then it's added into guc->capture->outlist linked
978 * list. This list is used for matchup and printout by xe_devcoredump_read
979 * and xe_engine_snapshot_print, (when user invokes the devcoredump sysfs).
980 *
981 * GUC --> notify context reset:
982 * -----------------------------
983 * --> guc_exec_queue_timedout_job
984 * L--> xe_devcoredump
985 * L--> devcoredump_snapshot
986 * --> xe_hw_engine_snapshot_capture
987 * --> xe_engine_manual_capture(For manual capture)
988 *
989 * User Sysfs / Debugfs
990 * --------------------
991 * --> xe_devcoredump_read->
992 * L--> xxx_snapshot_print
993 * L--> xe_engine_snapshot_print
994 * Print register lists values saved at
995 * guc->capture->outlist
996 *
997 */
998
guc_capture_buf_cnt(struct __guc_capture_bufstate * buf)999 static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
1000 {
1001 if (buf->wr >= buf->rd)
1002 return (buf->wr - buf->rd);
1003 return (buf->size - buf->rd) + buf->wr;
1004 }
1005
guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate * buf)1006 static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
1007 {
1008 if (buf->rd > buf->wr)
1009 return (buf->size - buf->rd);
1010 return (buf->wr - buf->rd);
1011 }
1012
1013 /*
1014 * GuC's error-capture output is a ring buffer populated in a byte-stream fashion:
1015 *
1016 * The GuC Log buffer region for error-capture is managed like a ring buffer.
1017 * The GuC firmware dumps error capture logs into this ring in a byte-stream flow.
1018 * Additionally, as per the current and foreseeable future, all packed error-
1019 * capture output structures are dword aligned.
1020 *
1021 * That said, if the GuC firmware is in the midst of writing a structure that is larger
1022 * than one dword but the tail end of the err-capture buffer-region has lesser space left,
1023 * we would need to extract that structure one dword at a time straddled across the end,
1024 * onto the start of the ring.
1025 *
1026 * Below function, guc_capture_log_remove_bytes is a helper for that. All callers of this
1027 * function would typically do a straight-up memcpy from the ring contents and will only
1028 * call this helper if their structure-extraction is straddling across the end of the
1029 * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease
1030 * scalability for future expansion of output data types without requiring a redesign
1031 * of the flow controls.
1032 */
1033 static int
guc_capture_log_remove_bytes(struct xe_guc * guc,struct __guc_capture_bufstate * buf,void * out,int bytes_needed)1034 guc_capture_log_remove_bytes(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
1035 void *out, int bytes_needed)
1036 {
1037 #define GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX 3
1038
1039 int fill_size = 0, tries = GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX;
1040 int copy_size, avail;
1041
1042 xe_assert(guc_to_xe(guc), bytes_needed % sizeof(u32) == 0);
1043
1044 if (bytes_needed > guc_capture_buf_cnt(buf))
1045 return -1;
1046
1047 while (bytes_needed > 0 && tries--) {
1048 int misaligned;
1049
1050 avail = guc_capture_buf_cnt_to_end(buf);
1051 misaligned = avail % sizeof(u32);
1052 /* wrap if at end */
1053 if (!avail) {
1054 /* output stream clipped */
1055 if (!buf->rd)
1056 return fill_size;
1057 buf->rd = 0;
1058 continue;
1059 }
1060
1061 /* Only copy to u32 aligned data */
1062 copy_size = avail < bytes_needed ? avail - misaligned : bytes_needed;
1063 xe_map_memcpy_from(guc_to_xe(guc), out + fill_size, &guc->log.bo->vmap,
1064 buf->data_offset + buf->rd, copy_size);
1065 buf->rd += copy_size;
1066 fill_size += copy_size;
1067 bytes_needed -= copy_size;
1068
1069 if (misaligned)
1070 xe_gt_warn(guc_to_gt(guc),
1071 "Bytes extraction not dword aligned, clipping.\n");
1072 }
1073
1074 return fill_size;
1075 }
1076
1077 static int
guc_capture_log_get_group_hdr(struct xe_guc * guc,struct __guc_capture_bufstate * buf,struct guc_state_capture_group_header_t * ghdr)1078 guc_capture_log_get_group_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
1079 struct guc_state_capture_group_header_t *ghdr)
1080 {
1081 int fullsize = sizeof(struct guc_state_capture_group_header_t);
1082
1083 if (guc_capture_log_remove_bytes(guc, buf, ghdr, fullsize) != fullsize)
1084 return -1;
1085 return 0;
1086 }
1087
1088 static int
guc_capture_log_get_data_hdr(struct xe_guc * guc,struct __guc_capture_bufstate * buf,struct guc_state_capture_header_t * hdr)1089 guc_capture_log_get_data_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
1090 struct guc_state_capture_header_t *hdr)
1091 {
1092 int fullsize = sizeof(struct guc_state_capture_header_t);
1093
1094 if (guc_capture_log_remove_bytes(guc, buf, hdr, fullsize) != fullsize)
1095 return -1;
1096 return 0;
1097 }
1098
1099 static int
guc_capture_log_get_register(struct xe_guc * guc,struct __guc_capture_bufstate * buf,struct guc_mmio_reg * reg)1100 guc_capture_log_get_register(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
1101 struct guc_mmio_reg *reg)
1102 {
1103 int fullsize = sizeof(struct guc_mmio_reg);
1104
1105 if (guc_capture_log_remove_bytes(guc, buf, reg, fullsize) != fullsize)
1106 return -1;
1107 return 0;
1108 }
1109
1110 static struct __guc_capture_parsed_output *
guc_capture_get_prealloc_node(struct xe_guc * guc)1111 guc_capture_get_prealloc_node(struct xe_guc *guc)
1112 {
1113 struct __guc_capture_parsed_output *found = NULL;
1114
1115 if (!list_empty(&guc->capture->cachelist)) {
1116 struct __guc_capture_parsed_output *n, *ntmp;
1117
1118 /* get first avail node from the cache list */
1119 list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) {
1120 found = n;
1121 break;
1122 }
1123 } else {
1124 struct __guc_capture_parsed_output *n, *ntmp;
1125
1126 /*
1127 * traverse reversed and steal back the oldest node already
1128 * allocated
1129 */
1130 list_for_each_entry_safe_reverse(n, ntmp, &guc->capture->outlist, link) {
1131 if (!n->locked)
1132 found = n;
1133 }
1134 }
1135 if (found) {
1136 list_del(&found->link);
1137 guc_capture_init_node(guc, found);
1138 }
1139
1140 return found;
1141 }
1142
1143 static struct __guc_capture_parsed_output *
guc_capture_clone_node(struct xe_guc * guc,struct __guc_capture_parsed_output * original,u32 keep_reglist_mask)1144 guc_capture_clone_node(struct xe_guc *guc, struct __guc_capture_parsed_output *original,
1145 u32 keep_reglist_mask)
1146 {
1147 struct __guc_capture_parsed_output *new;
1148 int i;
1149
1150 new = guc_capture_get_prealloc_node(guc);
1151 if (!new)
1152 return NULL;
1153 if (!original)
1154 return new;
1155
1156 new->is_partial = original->is_partial;
1157
1158 /* copy reg-lists that we want to clone */
1159 for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1160 if (keep_reglist_mask & BIT(i)) {
1161 XE_WARN_ON(original->reginfo[i].num_regs >
1162 guc->capture->max_mmio_per_node);
1163
1164 memcpy(new->reginfo[i].regs, original->reginfo[i].regs,
1165 original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg));
1166
1167 new->reginfo[i].num_regs = original->reginfo[i].num_regs;
1168 new->reginfo[i].vfid = original->reginfo[i].vfid;
1169
1170 if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) {
1171 new->eng_class = original->eng_class;
1172 } else if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
1173 new->eng_inst = original->eng_inst;
1174 new->guc_id = original->guc_id;
1175 new->lrca = original->lrca;
1176 }
1177 }
1178 }
1179
1180 return new;
1181 }
1182
1183 static int
guc_capture_extract_reglists(struct xe_guc * guc,struct __guc_capture_bufstate * buf)1184 guc_capture_extract_reglists(struct xe_guc *guc, struct __guc_capture_bufstate *buf)
1185 {
1186 struct xe_gt *gt = guc_to_gt(guc);
1187 struct guc_state_capture_group_header_t ghdr = {0};
1188 struct guc_state_capture_header_t hdr = {0};
1189 struct __guc_capture_parsed_output *node = NULL;
1190 struct guc_mmio_reg *regs = NULL;
1191 int i, numlists, numregs, ret = 0;
1192 enum guc_state_capture_type datatype;
1193 struct guc_mmio_reg tmp;
1194 bool is_partial = false;
1195
1196 i = guc_capture_buf_cnt(buf);
1197 if (!i)
1198 return -ENODATA;
1199
1200 if (i % sizeof(u32)) {
1201 xe_gt_warn(gt, "Got mis-aligned register capture entries\n");
1202 ret = -EIO;
1203 goto bailout;
1204 }
1205
1206 /* first get the capture group header */
1207 if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {
1208 ret = -EIO;
1209 goto bailout;
1210 }
1211 /*
1212 * we would typically expect a layout as below where n would be expected to be
1213 * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine
1214 * instances being reset together.
1215 * ____________________________________________
1216 * | Capture Group |
1217 * | ________________________________________ |
1218 * | | Capture Group Header: | |
1219 * | | - num_captures = 5 | |
1220 * | |______________________________________| |
1221 * | ________________________________________ |
1222 * | | Capture1: | |
1223 * | | Hdr: GLOBAL, numregs=a | |
1224 * | | ____________________________________ | |
1225 * | | | Reglist | | |
1226 * | | | - reg1, reg2, ... rega | | |
1227 * | | |__________________________________| | |
1228 * | |______________________________________| |
1229 * | ________________________________________ |
1230 * | | Capture2: | |
1231 * | | Hdr: CLASS=RENDER/COMPUTE, numregs=b| |
1232 * | | ____________________________________ | |
1233 * | | | Reglist | | |
1234 * | | | - reg1, reg2, ... regb | | |
1235 * | | |__________________________________| | |
1236 * | |______________________________________| |
1237 * | ________________________________________ |
1238 * | | Capture3: | |
1239 * | | Hdr: INSTANCE=RCS, numregs=c | |
1240 * | | ____________________________________ | |
1241 * | | | Reglist | | |
1242 * | | | - reg1, reg2, ... regc | | |
1243 * | | |__________________________________| | |
1244 * | |______________________________________| |
1245 * | ________________________________________ |
1246 * | | Capture4: | |
1247 * | | Hdr: CLASS=RENDER/COMPUTE, numregs=d| |
1248 * | | ____________________________________ | |
1249 * | | | Reglist | | |
1250 * | | | - reg1, reg2, ... regd | | |
1251 * | | |__________________________________| | |
1252 * | |______________________________________| |
1253 * | ________________________________________ |
1254 * | | Capture5: | |
1255 * | | Hdr: INSTANCE=CCS0, numregs=e | |
1256 * | | ____________________________________ | |
1257 * | | | Reglist | | |
1258 * | | | - reg1, reg2, ... rege | | |
1259 * | | |__________________________________| | |
1260 * | |______________________________________| |
1261 * |__________________________________________|
1262 */
1263 is_partial = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE, ghdr.info);
1264 numlists = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES, ghdr.info);
1265
1266 while (numlists--) {
1267 if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {
1268 ret = -EIO;
1269 break;
1270 }
1271
1272 datatype = FIELD_GET(GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE, hdr.info);
1273 if (datatype > GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
1274 /* unknown capture type - skip over to next capture set */
1275 numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
1276 hdr.num_mmio_entries);
1277 while (numregs--) {
1278 if (guc_capture_log_get_register(guc, buf, &tmp)) {
1279 ret = -EIO;
1280 break;
1281 }
1282 }
1283 continue;
1284 } else if (node) {
1285 /*
1286 * Based on the current capture type and what we have so far,
1287 * decide if we should add the current node into the internal
1288 * linked list for match-up when xe_devcoredump calls later
1289 * (and alloc a blank node for the next set of reglists)
1290 * or continue with the same node or clone the current node
1291 * but only retain the global or class registers (such as the
1292 * case of dependent engine resets).
1293 */
1294 if (datatype == GUC_STATE_CAPTURE_TYPE_GLOBAL) {
1295 guc_capture_add_node_to_outlist(guc->capture, node);
1296 node = NULL;
1297 } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
1298 node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS].num_regs) {
1299 /* Add to list, clone node and duplicate global list */
1300 guc_capture_add_node_to_outlist(guc->capture, node);
1301 node = guc_capture_clone_node(guc, node,
1302 GCAP_PARSED_REGLIST_INDEX_GLOBAL);
1303 } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE &&
1304 node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE].num_regs) {
1305 /* Add to list, clone node and duplicate global + class lists */
1306 guc_capture_add_node_to_outlist(guc->capture, node);
1307 node = guc_capture_clone_node(guc, node,
1308 (GCAP_PARSED_REGLIST_INDEX_GLOBAL |
1309 GCAP_PARSED_REGLIST_INDEX_ENGCLASS));
1310 }
1311 }
1312
1313 if (!node) {
1314 node = guc_capture_get_prealloc_node(guc);
1315 if (!node) {
1316 ret = -ENOMEM;
1317 break;
1318 }
1319 if (datatype != GUC_STATE_CAPTURE_TYPE_GLOBAL)
1320 xe_gt_dbg(gt, "Register capture missing global dump: %08x!\n",
1321 datatype);
1322 }
1323 node->is_partial = is_partial;
1324 node->reginfo[datatype].vfid = FIELD_GET(GUC_STATE_CAPTURE_HEADER_VFID, hdr.owner);
1325 node->source = XE_ENGINE_CAPTURE_SOURCE_GUC;
1326 node->type = datatype;
1327
1328 switch (datatype) {
1329 case GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE:
1330 node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
1331 hdr.info);
1332 node->eng_inst = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE,
1333 hdr.info);
1334 node->lrca = hdr.lrca;
1335 node->guc_id = hdr.guc_id;
1336 break;
1337 case GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS:
1338 node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
1339 hdr.info);
1340 break;
1341 default:
1342 break;
1343 }
1344
1345 numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
1346 hdr.num_mmio_entries);
1347 if (numregs > guc->capture->max_mmio_per_node) {
1348 xe_gt_dbg(gt, "Register capture list extraction clipped by prealloc!\n");
1349 numregs = guc->capture->max_mmio_per_node;
1350 }
1351 node->reginfo[datatype].num_regs = numregs;
1352 regs = node->reginfo[datatype].regs;
1353 i = 0;
1354 while (numregs--) {
1355 if (guc_capture_log_get_register(guc, buf, ®s[i++])) {
1356 ret = -EIO;
1357 break;
1358 }
1359 }
1360 }
1361
1362 bailout:
1363 if (node) {
1364 /* If we have data, add to linked list for match-up when xe_devcoredump calls */
1365 for (i = GUC_STATE_CAPTURE_TYPE_GLOBAL; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1366 if (node->reginfo[i].regs) {
1367 guc_capture_add_node_to_outlist(guc->capture, node);
1368 node = NULL;
1369 break;
1370 }
1371 }
1372 if (node) /* else return it back to cache list */
1373 guc_capture_add_node_to_cachelist(guc->capture, node);
1374 }
1375 return ret;
1376 }
1377
__guc_capture_flushlog_complete(struct xe_guc * guc)1378 static int __guc_capture_flushlog_complete(struct xe_guc *guc)
1379 {
1380 u32 action[] = {
1381 XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE,
1382 GUC_LOG_TYPE_STATE_CAPTURE
1383 };
1384
1385 return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action));
1386 }
1387
__guc_capture_process_output(struct xe_guc * guc)1388 static void __guc_capture_process_output(struct xe_guc *guc)
1389 {
1390 unsigned int buffer_size, read_offset, write_offset, full_count;
1391 struct xe_uc *uc = container_of(guc, typeof(*uc), guc);
1392 struct guc_log_buffer_state log_buf_state_local;
1393 struct __guc_capture_bufstate buf;
1394 bool new_overflow;
1395 int ret, tmp;
1396 u32 log_buf_state_offset;
1397 u32 src_data_offset;
1398
1399 log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_TYPE_STATE_CAPTURE;
1400 src_data_offset = XE_GUC_LOG_STATE_CAPTURE_OFFSET;
1401
1402 /*
1403 * Make a copy of the state structure, inside GuC log buffer
1404 * (which is uncached mapped), on the stack to avoid reading
1405 * from it multiple times.
1406 */
1407 xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap,
1408 log_buf_state_offset, sizeof(struct guc_log_buffer_state));
1409
1410 buffer_size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE;
1411 read_offset = log_buf_state_local.read_ptr;
1412 write_offset = log_buf_state_local.sampled_write_ptr;
1413 full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags);
1414
1415 /* Bookkeeping stuff */
1416 tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags);
1417 guc->log.stats[GUC_LOG_TYPE_STATE_CAPTURE].flush += tmp;
1418 new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_TYPE_STATE_CAPTURE,
1419 full_count);
1420
1421 /* Now copy the actual logs. */
1422 if (unlikely(new_overflow)) {
1423 /* copy the whole buffer in case of overflow */
1424 read_offset = 0;
1425 write_offset = buffer_size;
1426 } else if (unlikely((read_offset > buffer_size) ||
1427 (write_offset > buffer_size))) {
1428 xe_gt_err(guc_to_gt(guc),
1429 "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n",
1430 read_offset, buffer_size);
1431 /* copy whole buffer as offsets are unreliable */
1432 read_offset = 0;
1433 write_offset = buffer_size;
1434 }
1435
1436 buf.size = buffer_size;
1437 buf.rd = read_offset;
1438 buf.wr = write_offset;
1439 buf.data_offset = src_data_offset;
1440
1441 if (!xe_guc_read_stopped(guc)) {
1442 do {
1443 ret = guc_capture_extract_reglists(guc, &buf);
1444 if (ret && ret != -ENODATA)
1445 xe_gt_dbg(guc_to_gt(guc), "Capture extraction failed:%d\n", ret);
1446 } while (ret >= 0);
1447 }
1448
1449 /* Update the state of log buffer err-cap state */
1450 xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
1451 log_buf_state_offset + offsetof(struct guc_log_buffer_state, read_ptr), u32,
1452 write_offset);
1453
1454 /*
1455 * Clear the flush_to_file from local first, the local was loaded by above
1456 * xe_map_memcpy_from, then write out the "updated local" through
1457 * xe_map_wr()
1458 */
1459 log_buf_state_local.flags &= ~GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE;
1460 xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
1461 log_buf_state_offset + offsetof(struct guc_log_buffer_state, flags), u32,
1462 log_buf_state_local.flags);
1463 __guc_capture_flushlog_complete(guc);
1464 }
1465
1466 /*
1467 * xe_guc_capture_process - Process GuC register captured data
1468 * @guc: The GuC object
1469 *
1470 * When GuC captured data is ready, GuC will send message
1471 * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be
1472 * called to process the data comes with the message.
1473 *
1474 * Returns: None
1475 */
xe_guc_capture_process(struct xe_guc * guc)1476 void xe_guc_capture_process(struct xe_guc *guc)
1477 {
1478 if (guc->capture)
1479 __guc_capture_process_output(guc);
1480 }
1481
1482 static struct __guc_capture_parsed_output *
guc_capture_alloc_one_node(struct xe_guc * guc)1483 guc_capture_alloc_one_node(struct xe_guc *guc)
1484 {
1485 struct drm_device *drm = guc_to_drm(guc);
1486 struct __guc_capture_parsed_output *new;
1487 int i;
1488
1489 new = drmm_kzalloc(drm, sizeof(*new), GFP_KERNEL);
1490 if (!new)
1491 return NULL;
1492
1493 for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
1494 new->reginfo[i].regs = drmm_kzalloc(drm, guc->capture->max_mmio_per_node *
1495 sizeof(struct guc_mmio_reg), GFP_KERNEL);
1496 if (!new->reginfo[i].regs) {
1497 while (i)
1498 drmm_kfree(drm, new->reginfo[--i].regs);
1499 drmm_kfree(drm, new);
1500 return NULL;
1501 }
1502 }
1503 guc_capture_init_node(guc, new);
1504
1505 return new;
1506 }
1507
1508 static void
__guc_capture_create_prealloc_nodes(struct xe_guc * guc)1509 __guc_capture_create_prealloc_nodes(struct xe_guc *guc)
1510 {
1511 struct __guc_capture_parsed_output *node = NULL;
1512 int i;
1513
1514 for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) {
1515 node = guc_capture_alloc_one_node(guc);
1516 if (!node) {
1517 xe_gt_warn(guc_to_gt(guc), "Register capture pre-alloc-cache failure\n");
1518 /* dont free the priors, use what we got and cleanup at shutdown */
1519 return;
1520 }
1521 guc_capture_add_node_to_cachelist(guc->capture, node);
1522 }
1523 }
1524
1525 static int
guc_get_max_reglist_count(struct xe_guc * guc)1526 guc_get_max_reglist_count(struct xe_guc *guc)
1527 {
1528 int i, j, k, tmp, maxregcount = 0;
1529
1530 for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {
1531 for (j = 0; j < GUC_STATE_CAPTURE_TYPE_MAX; ++j) {
1532 for (k = 0; k < GUC_CAPTURE_LIST_CLASS_MAX; ++k) {
1533 const struct __guc_mmio_reg_descr_group *match;
1534
1535 if (j == GUC_STATE_CAPTURE_TYPE_GLOBAL && k > 0)
1536 continue;
1537
1538 tmp = 0;
1539 match = guc_capture_get_one_list(guc->capture->reglists, i, j, k);
1540 if (match)
1541 tmp = match->num_regs;
1542
1543 match = guc_capture_get_one_list(guc->capture->extlists, i, j, k);
1544 if (match)
1545 tmp += match->num_regs;
1546
1547 if (tmp > maxregcount)
1548 maxregcount = tmp;
1549 }
1550 }
1551 }
1552 if (!maxregcount)
1553 maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS;
1554
1555 return maxregcount;
1556 }
1557
1558 static void
guc_capture_create_prealloc_nodes(struct xe_guc * guc)1559 guc_capture_create_prealloc_nodes(struct xe_guc *guc)
1560 {
1561 /* skip if we've already done the pre-alloc */
1562 if (guc->capture->max_mmio_per_node)
1563 return;
1564
1565 guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc);
1566 __guc_capture_create_prealloc_nodes(guc);
1567 }
1568
1569 static void
read_reg_to_node(struct xe_hw_engine * hwe,const struct __guc_mmio_reg_descr_group * list,struct guc_mmio_reg * regs)1570 read_reg_to_node(struct xe_hw_engine *hwe, const struct __guc_mmio_reg_descr_group *list,
1571 struct guc_mmio_reg *regs)
1572 {
1573 int i;
1574
1575 if (!list || !list->list || list->num_regs == 0)
1576 return;
1577
1578 if (!regs)
1579 return;
1580
1581 for (i = 0; i < list->num_regs; i++) {
1582 struct __guc_mmio_reg_descr desc = list->list[i];
1583 u32 value;
1584
1585 if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
1586 value = xe_hw_engine_mmio_read32(hwe, desc.reg);
1587 } else {
1588 if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
1589 FIELD_GET(GUC_REGSET_STEERING_NEEDED, desc.flags)) {
1590 int group, instance;
1591
1592 group = FIELD_GET(GUC_REGSET_STEERING_GROUP, desc.flags);
1593 instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, desc.flags);
1594 value = xe_gt_mcr_unicast_read(hwe->gt, XE_REG_MCR(desc.reg.addr),
1595 group, instance);
1596 } else {
1597 value = xe_mmio_read32(&hwe->gt->mmio, desc.reg);
1598 }
1599 }
1600
1601 regs[i].value = value;
1602 regs[i].offset = desc.reg.addr;
1603 regs[i].flags = desc.flags;
1604 regs[i].mask = desc.mask;
1605 }
1606 }
1607
1608 /**
1609 * xe_engine_manual_capture - Take a manual engine snapshot from engine.
1610 * @hwe: Xe HW Engine.
1611 * @snapshot: The engine snapshot
1612 *
1613 * Take engine snapshot from engine read.
1614 *
1615 * Returns: None
1616 */
1617 void
xe_engine_manual_capture(struct xe_hw_engine * hwe,struct xe_hw_engine_snapshot * snapshot)1618 xe_engine_manual_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot)
1619 {
1620 struct xe_gt *gt = hwe->gt;
1621 struct xe_device *xe = gt_to_xe(gt);
1622 struct xe_guc *guc = >->uc.guc;
1623 struct xe_devcoredump *devcoredump = &xe->devcoredump;
1624 enum guc_capture_list_class_type capture_class;
1625 const struct __guc_mmio_reg_descr_group *list;
1626 struct __guc_capture_parsed_output *new;
1627 enum guc_state_capture_type type;
1628 u16 guc_id = 0;
1629 u32 lrca = 0;
1630
1631 if (IS_SRIOV_VF(xe))
1632 return;
1633
1634 new = guc_capture_get_prealloc_node(guc);
1635 if (!new)
1636 return;
1637
1638 capture_class = xe_hwe_to_guc_capture_class(hwe);
1639 for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) {
1640 struct gcap_reg_list_info *reginfo = &new->reginfo[type];
1641 /*
1642 * regsinfo->regs is allocated based on guc->capture->max_mmio_per_node
1643 * which is based on the descriptor list driving the population so
1644 * should not overflow
1645 */
1646
1647 /* Get register list for the type/class */
1648 list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type,
1649 capture_class, false);
1650 if (!list) {
1651 xe_gt_dbg(gt, "Empty GuC capture register descriptor for %s",
1652 hwe->name);
1653 continue;
1654 }
1655
1656 read_reg_to_node(hwe, list, reginfo->regs);
1657 reginfo->num_regs = list->num_regs;
1658
1659 /* Capture steering registers for rcs/ccs */
1660 if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
1661 list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF,
1662 type, capture_class, true);
1663 if (list) {
1664 read_reg_to_node(hwe, list, ®info->regs[reginfo->num_regs]);
1665 reginfo->num_regs += list->num_regs;
1666 }
1667 }
1668 }
1669
1670 if (devcoredump && devcoredump->captured) {
1671 struct xe_guc_submit_exec_queue_snapshot *ge = devcoredump->snapshot.ge;
1672
1673 if (ge) {
1674 guc_id = ge->guc.id;
1675 if (ge->lrc[0])
1676 lrca = ge->lrc[0]->context_desc;
1677 }
1678 }
1679
1680 new->eng_class = xe_hwe_to_guc_class(hwe);
1681 new->eng_inst = hwe->instance;
1682 new->guc_id = guc_id;
1683 new->lrca = lrca;
1684 new->is_partial = 0;
1685 new->locked = 1;
1686 new->source = XE_ENGINE_CAPTURE_SOURCE_MANUAL;
1687
1688 guc_capture_add_node_to_outlist(guc->capture, new);
1689 devcoredump->snapshot.matched_node = new;
1690 }
1691
1692 static struct guc_mmio_reg *
guc_capture_find_reg(struct gcap_reg_list_info * reginfo,u32 addr,u32 flags)1693 guc_capture_find_reg(struct gcap_reg_list_info *reginfo, u32 addr, u32 flags)
1694 {
1695 int i;
1696
1697 if (reginfo && reginfo->num_regs > 0) {
1698 struct guc_mmio_reg *regs = reginfo->regs;
1699
1700 if (regs)
1701 for (i = 0; i < reginfo->num_regs; i++)
1702 if (regs[i].offset == addr && regs[i].flags == flags)
1703 return ®s[i];
1704 }
1705
1706 return NULL;
1707 }
1708
1709 static void
snapshot_print_by_list_order(struct xe_hw_engine_snapshot * snapshot,struct drm_printer * p,u32 type,const struct __guc_mmio_reg_descr_group * list)1710 snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p,
1711 u32 type, const struct __guc_mmio_reg_descr_group *list)
1712 {
1713 struct xe_gt *gt = snapshot->hwe->gt;
1714 struct xe_device *xe = gt_to_xe(gt);
1715 struct xe_devcoredump *devcoredump = &xe->devcoredump;
1716 struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot;
1717 struct gcap_reg_list_info *reginfo = NULL;
1718 u32 i, last_value = 0;
1719 bool low32_ready = false;
1720
1721 if (!list || !list->list || list->num_regs == 0)
1722 return;
1723 XE_WARN_ON(!devcore_snapshot->matched_node);
1724
1725 reginfo = &devcore_snapshot->matched_node->reginfo[type];
1726
1727 /*
1728 * loop through descriptor first and find the register in the node
1729 * this is more scalable for developer maintenance as it will ensure
1730 * the printout matched the ordering of the static descriptor
1731 * table-of-lists
1732 */
1733 for (i = 0; i < list->num_regs; i++) {
1734 const struct __guc_mmio_reg_descr *reg_desc = &list->list[i];
1735 struct guc_mmio_reg *reg;
1736 u32 value;
1737
1738 reg = guc_capture_find_reg(reginfo, reg_desc->reg.addr, reg_desc->flags);
1739 if (!reg)
1740 continue;
1741
1742 value = reg->value;
1743 switch (reg_desc->data_type) {
1744 case REG_64BIT_LOW_DW:
1745 last_value = value;
1746
1747 /*
1748 * A 64 bit register define requires 2 consecutive
1749 * entries in register list, with low dword first
1750 * and hi dword the second, like:
1751 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1752 * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, "XXX_REG"},
1753 *
1754 * Incorrect order will trigger XE_WARN.
1755 *
1756 * Possible double low here, for example:
1757 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1758 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1759 */
1760 XE_WARN_ON(low32_ready);
1761 low32_ready = true;
1762 /* Low 32 bit dword saved, continue for high 32 bit */
1763 break;
1764
1765 case REG_64BIT_HI_DW: {
1766 u64 value_qw = ((u64)value << 32) | last_value;
1767
1768 /*
1769 * Incorrect 64bit register order. Possible missing low.
1770 * for example:
1771 * { XXX_REG(0), REG_32BIT, 0, 0, NULL},
1772 * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, NULL},
1773 */
1774 XE_WARN_ON(!low32_ready);
1775 low32_ready = false;
1776
1777 drm_printf(p, "\t%s: 0x%016llx\n", reg_desc->regname, value_qw);
1778 break;
1779 }
1780
1781 case REG_32BIT:
1782 /*
1783 * Incorrect 64bit register order. Possible missing high.
1784 * for example:
1785 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1786 * { XXX_REG(0), REG_32BIT, 0, 0, "XXX_REG"},
1787 */
1788 XE_WARN_ON(low32_ready);
1789
1790 if (FIELD_GET(GUC_REGSET_STEERING_NEEDED, reg_desc->flags))
1791 drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname,
1792 reg_desc->dss_id, value);
1793 else
1794 drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value);
1795
1796 break;
1797 }
1798 }
1799
1800 /*
1801 * Incorrect 64bit register order. Possible missing high.
1802 * for example:
1803 * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1804 * } // <- Register list end
1805 */
1806 XE_WARN_ON(low32_ready);
1807 }
1808
1809 /**
1810 * xe_engine_snapshot_print - Print out a given Xe HW Engine snapshot.
1811 * @snapshot: Xe HW Engine snapshot object.
1812 * @p: drm_printer where it will be printed out.
1813 *
1814 * This function prints out a given Xe HW Engine snapshot object.
1815 */
xe_engine_snapshot_print(struct xe_hw_engine_snapshot * snapshot,struct drm_printer * p)1816 void xe_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p)
1817 {
1818 const char *grptype[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {
1819 "full-capture",
1820 "partial-capture"
1821 };
1822 int type;
1823 const struct __guc_mmio_reg_descr_group *list;
1824 enum guc_capture_list_class_type capture_class;
1825
1826 struct xe_gt *gt;
1827 struct xe_device *xe;
1828 struct xe_devcoredump *devcoredump;
1829 struct xe_devcoredump_snapshot *devcore_snapshot;
1830
1831 if (!snapshot)
1832 return;
1833
1834 gt = snapshot->hwe->gt;
1835 xe = gt_to_xe(gt);
1836 devcoredump = &xe->devcoredump;
1837 devcore_snapshot = &devcoredump->snapshot;
1838
1839 if (!devcore_snapshot->matched_node)
1840 return;
1841
1842 xe_gt_assert(gt, snapshot->hwe);
1843
1844 capture_class = xe_hwe_to_guc_capture_class(snapshot->hwe);
1845
1846 drm_printf(p, "%s (physical), logical instance=%d\n",
1847 snapshot->name ? snapshot->name : "",
1848 snapshot->logical_instance);
1849 drm_printf(p, "\tCapture_source: %s\n",
1850 devcore_snapshot->matched_node->source == XE_ENGINE_CAPTURE_SOURCE_GUC ?
1851 "GuC" : "Manual");
1852 drm_printf(p, "\tCoverage: %s\n", grptype[devcore_snapshot->matched_node->is_partial]);
1853 drm_printf(p, "\tForcewake: domain 0x%x, ref %d\n",
1854 snapshot->forcewake.domain, snapshot->forcewake.ref);
1855 drm_printf(p, "\tReserved: %s\n",
1856 str_yes_no(snapshot->kernel_reserved));
1857
1858 for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) {
1859 list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type,
1860 capture_class, false);
1861 snapshot_print_by_list_order(snapshot, p, type, list);
1862 }
1863
1864 if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
1865 list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF,
1866 GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
1867 capture_class, true);
1868 snapshot_print_by_list_order(snapshot, p, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
1869 list);
1870 }
1871
1872 drm_puts(p, "\n");
1873 }
1874
1875 /**
1876 * xe_guc_capture_get_matching_and_lock - Matching GuC capture for the queue.
1877 * @q: The exec queue object
1878 *
1879 * Search within the capture outlist for the queue, could be used for check if
1880 * GuC capture is ready for the queue.
1881 * If found, the locked boolean of the node will be flagged.
1882 *
1883 * Returns: found guc-capture node ptr else NULL
1884 */
1885 struct __guc_capture_parsed_output *
xe_guc_capture_get_matching_and_lock(struct xe_exec_queue * q)1886 xe_guc_capture_get_matching_and_lock(struct xe_exec_queue *q)
1887 {
1888 struct xe_hw_engine *hwe;
1889 enum xe_hw_engine_id id;
1890 struct xe_device *xe;
1891 u16 guc_class = GUC_LAST_ENGINE_CLASS + 1;
1892 struct xe_devcoredump_snapshot *ss;
1893
1894 if (!q || !q->gt)
1895 return NULL;
1896
1897 xe = gt_to_xe(q->gt);
1898
1899 if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
1900 return NULL;
1901
1902 if (!xe_device_uc_enabled(xe))
1903 return NULL;
1904
1905 if (IS_SRIOV_VF(xe))
1906 return NULL;
1907
1908 ss = &xe->devcoredump.snapshot;
1909 if (ss->matched_node && ss->matched_node->source == XE_ENGINE_CAPTURE_SOURCE_GUC)
1910 return ss->matched_node;
1911
1912 /* Find hwe for the queue */
1913 for_each_hw_engine(hwe, q->gt, id) {
1914 if (hwe != q->hwe)
1915 continue;
1916 guc_class = xe_hwe_to_guc_class(hwe);
1917 break;
1918 }
1919
1920 if (guc_class <= GUC_LAST_ENGINE_CLASS) {
1921 struct __guc_capture_parsed_output *n, *ntmp;
1922 struct xe_guc *guc = &q->gt->uc.guc;
1923 u16 guc_id = q->guc->id;
1924 u32 lrca = xe_lrc_ggtt_addr(q->lrc[0]);
1925
1926 /*
1927 * Look for a matching GuC reported error capture node from
1928 * the internal output link-list based on engine, guc id and
1929 * lrca info.
1930 */
1931 list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) {
1932 if (n->eng_class == guc_class && n->eng_inst == hwe->instance &&
1933 n->guc_id == guc_id && n->lrca == lrca &&
1934 n->source == XE_ENGINE_CAPTURE_SOURCE_GUC) {
1935 n->locked = 1;
1936 return n;
1937 }
1938 }
1939 }
1940 return NULL;
1941 }
1942
1943 /**
1944 * xe_engine_snapshot_capture_for_queue - Take snapshot of associated engine
1945 * @q: The exec queue object
1946 *
1947 * Take snapshot of associated HW Engine
1948 *
1949 * Returns: None.
1950 */
1951 void
xe_engine_snapshot_capture_for_queue(struct xe_exec_queue * q)1952 xe_engine_snapshot_capture_for_queue(struct xe_exec_queue *q)
1953 {
1954 struct xe_device *xe = gt_to_xe(q->gt);
1955 struct xe_devcoredump *coredump = &xe->devcoredump;
1956 struct xe_hw_engine *hwe;
1957 enum xe_hw_engine_id id;
1958 u32 adj_logical_mask = q->logical_mask;
1959
1960 if (IS_SRIOV_VF(xe))
1961 return;
1962
1963 for_each_hw_engine(hwe, q->gt, id) {
1964 if (hwe->class != q->hwe->class ||
1965 !(BIT(hwe->logical_instance) & adj_logical_mask)) {
1966 coredump->snapshot.hwe[id] = NULL;
1967 continue;
1968 }
1969
1970 if (!coredump->snapshot.hwe[id]) {
1971 coredump->snapshot.hwe[id] =
1972 xe_hw_engine_snapshot_capture(hwe, q);
1973 } else {
1974 struct __guc_capture_parsed_output *new;
1975
1976 new = xe_guc_capture_get_matching_and_lock(q);
1977 if (new) {
1978 struct xe_guc *guc = &q->gt->uc.guc;
1979
1980 /*
1981 * If we are in here, it means we found a fresh
1982 * GuC-err-capture node for this engine after
1983 * previously failing to find a match in the
1984 * early part of guc_exec_queue_timedout_job.
1985 * Thus we must free the manually captured node
1986 */
1987 guc_capture_free_outlist_node(guc->capture,
1988 coredump->snapshot.matched_node);
1989 coredump->snapshot.matched_node = new;
1990 }
1991 }
1992
1993 break;
1994 }
1995 }
1996
1997 /*
1998 * xe_guc_capture_put_matched_nodes - Cleanup matched nodes
1999 * @guc: The GuC object
2000 *
2001 * Free matched node and all nodes with the equal guc_id from
2002 * GuC captured outlist
2003 */
xe_guc_capture_put_matched_nodes(struct xe_guc * guc)2004 void xe_guc_capture_put_matched_nodes(struct xe_guc *guc)
2005 {
2006 struct xe_device *xe = guc_to_xe(guc);
2007 struct xe_devcoredump *devcoredump = &xe->devcoredump;
2008 struct __guc_capture_parsed_output *n = devcoredump->snapshot.matched_node;
2009
2010 if (n) {
2011 guc_capture_remove_stale_matches_from_list(guc->capture, n);
2012 guc_capture_free_outlist_node(guc->capture, n);
2013 devcoredump->snapshot.matched_node = NULL;
2014 }
2015 }
2016
2017 /*
2018 * xe_guc_capture_steered_list_init - Init steering register list
2019 * @guc: The GuC object
2020 *
2021 * Init steering register list for GuC register capture, create pre-alloc node
2022 */
xe_guc_capture_steered_list_init(struct xe_guc * guc)2023 void xe_guc_capture_steered_list_init(struct xe_guc *guc)
2024 {
2025 /*
2026 * For certain engine classes, there are slice and subslice
2027 * level registers requiring steering. We allocate and populate
2028 * these based on hw config and add it as an extension list at
2029 * the end of the pre-populated render list.
2030 */
2031 guc_capture_alloc_steered_lists(guc);
2032 check_guc_capture_size(guc);
2033 guc_capture_create_prealloc_nodes(guc);
2034 }
2035
2036 /*
2037 * xe_guc_capture_init - Init for GuC register capture
2038 * @guc: The GuC object
2039 *
2040 * Init for GuC register capture, alloc memory for capture data structure.
2041 *
2042 * Returns: 0 if success.
2043 * -ENOMEM if out of memory
2044 */
xe_guc_capture_init(struct xe_guc * guc)2045 int xe_guc_capture_init(struct xe_guc *guc)
2046 {
2047 guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL);
2048 if (!guc->capture)
2049 return -ENOMEM;
2050
2051 guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc));
2052
2053 INIT_LIST_HEAD(&guc->capture->outlist);
2054 INIT_LIST_HEAD(&guc->capture->cachelist);
2055
2056 return 0;
2057 }
2058