brintos

brintos / linux-shallow public Read only

0
0
Text · 50.3 KiB · 9547fff Raw
1655 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2021-2022 Intel Corporation4 */5 6#include <linux/types.h>7 8#include <drm/drm_print.h>9 10#include "gt/intel_engine_regs.h"11#include "gt/intel_gt.h"12#include "gt/intel_gt_mcr.h"13#include "gt/intel_gt_regs.h"14#include "gt/intel_lrc.h"15#include "guc_capture_fwif.h"16#include "intel_guc_capture.h"17#include "intel_guc_fwif.h"18#include "intel_guc_print.h"19#include "i915_drv.h"20#include "i915_gpu_error.h"21#include "i915_irq.h"22#include "i915_memcpy.h"23#include "i915_reg.h"24 25/*26 * Define all device tables of GuC error capture register lists27 * NOTE: For engine-registers, GuC only needs the register offsets28 *       from the engine-mmio-base29 */30#define COMMON_BASE_GLOBAL \31	{ FORCEWAKE_MT,             0,      0, "FORCEWAKE" }32 33#define COMMON_GEN8BASE_GLOBAL \34	{ ERROR_GEN6,               0,      0, "ERROR_GEN6" }, \35	{ DONE_REG,                 0,      0, "DONE_REG" }, \36	{ HSW_GTT_CACHE_EN,         0,      0, "HSW_GTT_CACHE_EN" }37 38#define GEN8_GLOBAL \39	{ GEN8_FAULT_TLB_DATA0,     0,      0, "GEN8_FAULT_TLB_DATA0" }, \40	{ GEN8_FAULT_TLB_DATA1,     0,      0, "GEN8_FAULT_TLB_DATA1" }41 42#define COMMON_GEN12BASE_GLOBAL \43	{ GEN12_FAULT_TLB_DATA0,    0,      0, "GEN12_FAULT_TLB_DATA0" }, \44	{ GEN12_FAULT_TLB_DATA1,    0,      0, "GEN12_FAULT_TLB_DATA1" }, \45	{ GEN12_AUX_ERR_DBG,        0,      0, "AUX_ERR_DBG" }, \46	{ GEN12_GAM_DONE,           0,      0, "GAM_DONE" }, \47	{ GEN12_RING_FAULT_REG,     0,      0, "FAULT_REG" }48 49#define COMMON_BASE_ENGINE_INSTANCE \50	{ RING_PSMI_CTL(0),         0,      0, "RC PSMI" }, \51	{ RING_ESR(0),              0,      0, "ESR" }, \52	{ RING_DMA_FADD(0),         0,      0, "RING_DMA_FADD_LDW" }, \53	{ RING_DMA_FADD_UDW(0),     0,      0, "RING_DMA_FADD_UDW" }, \54	{ RING_EIR(0),              0,      0, "EIR" }, \55	{ RING_IPEIR(0),            0,      0, "IPEIR" }, \56	{ RING_IPEHR(0),            0,      0, "IPEHR" }, \57	{ RING_INSTPS(0),           0,      0, "INSTPS" }, \58	{ RING_BBADDR(0),           0,      0, "RING_BBADDR_LOW32" }, \59	{ RING_BBADDR_UDW(0),       0,      0, "RING_BBADDR_UP32" }, \60	{ RING_BBSTATE(0),          0,      0, "BB_STATE" }, \61	{ CCID(0),                  0,      0, "CCID" }, \62	{ RING_ACTHD(0),            0,      0, "ACTHD_LDW" }, \63	{ RING_ACTHD_UDW(0),        0,      0, "ACTHD_UDW" }, \64	{ RING_INSTPM(0),           0,      0, "INSTPM" }, \65	{ RING_INSTDONE(0),         0,      0, "INSTDONE" }, \66	{ RING_NOPID(0),            0,      0, "RING_NOPID" }, \67	{ RING_START(0),            0,      0, "START" }, \68	{ RING_HEAD(0),             0,      0, "HEAD" }, \69	{ RING_TAIL(0),             0,      0, "TAIL" }, \70	{ RING_CTL(0),              0,      0, "CTL" }, \71	{ RING_MI_MODE(0),          0,      0, "MODE" }, \72	{ RING_CONTEXT_CONTROL(0),  0,      0, "RING_CONTEXT_CONTROL" }, \73	{ RING_HWS_PGA(0),          0,      0, "HWS" }, \74	{ RING_MODE_GEN7(0),        0,      0, "GFX_MODE" }, \75	{ GEN8_RING_PDP_LDW(0, 0),  0,      0, "PDP0_LDW" }, \76	{ GEN8_RING_PDP_UDW(0, 0),  0,      0, "PDP0_UDW" }, \77	{ GEN8_RING_PDP_LDW(0, 1),  0,      0, "PDP1_LDW" }, \78	{ GEN8_RING_PDP_UDW(0, 1),  0,      0, "PDP1_UDW" }, \79	{ GEN8_RING_PDP_LDW(0, 2),  0,      0, "PDP2_LDW" }, \80	{ GEN8_RING_PDP_UDW(0, 2),  0,      0, "PDP2_UDW" }, \81	{ GEN8_RING_PDP_LDW(0, 3),  0,      0, "PDP3_LDW" }, \82	{ GEN8_RING_PDP_UDW(0, 3),  0,      0, "PDP3_UDW" }83 84#define COMMON_BASE_RENDER \85	{ GEN7_SC_INSTDONE,         0,      0, "GEN7_SC_INSTDONE" }86 87#define COMMON_GEN12BASE_RENDER \88	{ GEN12_SC_INSTDONE_EXTRA,  0,      0, "GEN12_SC_INSTDONE_EXTRA" }, \89	{ GEN12_SC_INSTDONE_EXTRA2, 0,      0, "GEN12_SC_INSTDONE_EXTRA2" }90 91#define COMMON_GEN12BASE_VEC \92	{ GEN12_SFC_DONE(0),        0,      0, "SFC_DONE[0]" }, \93	{ GEN12_SFC_DONE(1),        0,      0, "SFC_DONE[1]" }, \94	{ GEN12_SFC_DONE(2),        0,      0, "SFC_DONE[2]" }, \95	{ GEN12_SFC_DONE(3),        0,      0, "SFC_DONE[3]" }96 97/* XE_LP Global */98static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {99	COMMON_BASE_GLOBAL,100	COMMON_GEN8BASE_GLOBAL,101	COMMON_GEN12BASE_GLOBAL,102};103 104/* XE_LP Render / Compute Per-Class */105static const struct __guc_mmio_reg_descr xe_lp_rc_class_regs[] = {106	COMMON_BASE_RENDER,107	COMMON_GEN12BASE_RENDER,108};109 110/* GEN8+ Render / Compute Per-Engine-Instance */111static const struct __guc_mmio_reg_descr gen8_rc_inst_regs[] = {112	COMMON_BASE_ENGINE_INSTANCE,113};114 115/* GEN8+ Media Decode/Encode Per-Engine-Instance */116static const struct __guc_mmio_reg_descr gen8_vd_inst_regs[] = {117	COMMON_BASE_ENGINE_INSTANCE,118};119 120/* XE_LP Video Enhancement Per-Class */121static const struct __guc_mmio_reg_descr xe_lp_vec_class_regs[] = {122	COMMON_GEN12BASE_VEC,123};124 125/* GEN8+ Video Enhancement Per-Engine-Instance */126static const struct __guc_mmio_reg_descr gen8_vec_inst_regs[] = {127	COMMON_BASE_ENGINE_INSTANCE,128};129 130/* GEN8+ Blitter Per-Engine-Instance */131static const struct __guc_mmio_reg_descr gen8_blt_inst_regs[] = {132	COMMON_BASE_ENGINE_INSTANCE,133};134 135/* XE_LP - GSC Per-Engine-Instance */136static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {137	COMMON_BASE_ENGINE_INSTANCE,138};139 140/* GEN8 - Global */141static const struct __guc_mmio_reg_descr gen8_global_regs[] = {142	COMMON_BASE_GLOBAL,143	COMMON_GEN8BASE_GLOBAL,144	GEN8_GLOBAL,145};146 147static const struct __guc_mmio_reg_descr gen8_rc_class_regs[] = {148	COMMON_BASE_RENDER,149};150 151/*152 * Empty list to prevent warnings about unknown class/instance types153 * as not all class/instanace types have entries on all platforms.154 */155static const struct __guc_mmio_reg_descr empty_regs_list[] = {156};157 158#define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)159#define TO_GCAP_DEF_TYPE(x) (GUC_CAPTURE_LIST_TYPE_##x)160#define MAKE_REGLIST(regslist, regsowner, regstype, class) \161	{ \162		regslist, \163		ARRAY_SIZE(regslist), \164		TO_GCAP_DEF_OWNER(regsowner), \165		TO_GCAP_DEF_TYPE(regstype), \166		class, \167		NULL, \168	}169 170/* List of lists */171static const struct __guc_mmio_reg_descr_group gen8_lists[] = {172	MAKE_REGLIST(gen8_global_regs, PF, GLOBAL, 0),173	MAKE_REGLIST(gen8_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),174	MAKE_REGLIST(gen8_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),175	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),176	MAKE_REGLIST(gen8_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),177	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),178	MAKE_REGLIST(gen8_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),179	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),180	MAKE_REGLIST(gen8_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),181	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),182	MAKE_REGLIST(empty_regs_list, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),183	{}184};185 186static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {187	MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),188	MAKE_REGLIST(xe_lp_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),189	MAKE_REGLIST(gen8_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),190	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),191	MAKE_REGLIST(gen8_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),192	MAKE_REGLIST(xe_lp_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),193	MAKE_REGLIST(gen8_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),194	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),195	MAKE_REGLIST(gen8_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),196	MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),197	MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),198	{}199};200 201static const struct __guc_mmio_reg_descr_group *202guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,203			 u32 owner, u32 type, u32 id)204{205	int i;206 207	if (!reglists)208		return NULL;209 210	for (i = 0; reglists[i].list; ++i) {211		if (reglists[i].owner == owner && reglists[i].type == type &&212		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))213			return &reglists[i];214	}215 216	return NULL;217}218 219static struct __guc_mmio_reg_descr_group *220guc_capture_get_one_ext_list(struct __guc_mmio_reg_descr_group *reglists,221			     u32 owner, u32 type, u32 id)222{223	int i;224 225	if (!reglists)226		return NULL;227 228	for (i = 0; reglists[i].extlist; ++i) {229		if (reglists[i].owner == owner && reglists[i].type == type &&230		    (reglists[i].engine == id || reglists[i].type == GUC_CAPTURE_LIST_TYPE_GLOBAL))231			return &reglists[i];232	}233 234	return NULL;235}236 237static void guc_capture_free_extlists(struct __guc_mmio_reg_descr_group *reglists)238{239	int i = 0;240 241	if (!reglists)242		return;243 244	while (reglists[i].extlist)245		kfree(reglists[i++].extlist);246}247 248struct __ext_steer_reg {249	const char *name;250	i915_mcr_reg_t reg;251};252 253static const struct __ext_steer_reg gen8_extregs[] = {254	{"GEN8_SAMPLER_INSTDONE", GEN8_SAMPLER_INSTDONE},255	{"GEN8_ROW_INSTDONE", GEN8_ROW_INSTDONE}256};257 258static const struct __ext_steer_reg xehpg_extregs[] = {259	{"XEHPG_INSTDONE_GEOM_SVG", XEHPG_INSTDONE_GEOM_SVG}260};261 262static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,263			   const struct __ext_steer_reg *extlist,264			   int slice_id, int subslice_id)265{266	ext->reg = _MMIO(i915_mmio_reg_offset(extlist->reg));267	ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);268	ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);269	ext->regname = extlist->name;270}271 272static int273__alloc_ext_regs(struct __guc_mmio_reg_descr_group *newlist,274		 const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)275{276	struct __guc_mmio_reg_descr *list;277 278	list = kcalloc(num_regs, sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);279	if (!list)280		return -ENOMEM;281 282	newlist->extlist = list;283	newlist->num_regs = num_regs;284	newlist->owner = rootlist->owner;285	newlist->engine = rootlist->engine;286	newlist->type = rootlist->type;287 288	return 0;289}290 291static void292guc_capture_alloc_steered_lists(struct intel_guc *guc,293				const struct __guc_mmio_reg_descr_group *lists)294{295	struct intel_gt *gt = guc_to_gt(guc);296	int slice, subslice, iter, i, num_steer_regs, num_tot_regs = 0;297	const struct __guc_mmio_reg_descr_group *list;298	struct __guc_mmio_reg_descr_group *extlists;299	struct __guc_mmio_reg_descr *extarray;300	bool has_xehpg_extregs;301 302	/* steered registers currently only exist for the render-class */303	list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,304					GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,305					GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE);306	/* skip if extlists was previously allocated */307	if (!list || guc->capture->extlists)308		return;309 310	has_xehpg_extregs = GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 55);311 312	num_steer_regs = ARRAY_SIZE(gen8_extregs);313	if (has_xehpg_extregs)314		num_steer_regs += ARRAY_SIZE(xehpg_extregs);315 316	for_each_ss_steering(iter, gt, slice, subslice)317		num_tot_regs += num_steer_regs;318 319	if (!num_tot_regs)320		return;321 322	/* allocate an extra for an end marker */323	extlists = kcalloc(2, sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL);324	if (!extlists)325		return;326 327	if (__alloc_ext_regs(&extlists[0], list, num_tot_regs)) {328		kfree(extlists);329		return;330	}331 332	extarray = extlists[0].extlist;333	for_each_ss_steering(iter, gt, slice, subslice) {334		for (i = 0; i < ARRAY_SIZE(gen8_extregs); ++i) {335			__fill_ext_reg(extarray, &gen8_extregs[i], slice, subslice);336			++extarray;337		}338 339		if (has_xehpg_extregs) {340			for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {341				__fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice);342				++extarray;343			}344		}345	}346 347	guc_dbg(guc, "capture found %d ext-regs.\n", num_tot_regs);348	guc->capture->extlists = extlists;349}350 351static const struct __guc_mmio_reg_descr_group *352guc_capture_get_device_reglist(struct intel_guc *guc)353{354	struct drm_i915_private *i915 = guc_to_i915(guc);355	const struct __guc_mmio_reg_descr_group *lists;356 357	if (GRAPHICS_VER(i915) >= 12)358		lists = xe_lp_lists;359	else360		lists = gen8_lists;361 362	/*363	 * For certain engine classes, there are slice and subslice364	 * level registers requiring steering. We allocate and populate365	 * these at init time based on hw config add it as an extension366	 * list at the end of the pre-populated render list.367	 */368	guc_capture_alloc_steered_lists(guc, lists);369 370	return lists;371}372 373static const char *374__stringify_type(u32 type)375{376	switch (type) {377	case GUC_CAPTURE_LIST_TYPE_GLOBAL:378		return "Global";379	case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:380		return "Class";381	case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:382		return "Instance";383	default:384		break;385	}386 387	return "unknown";388}389 390static const char *391__stringify_engclass(u32 class)392{393	switch (class) {394	case GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE:395		return "Render/Compute";396	case GUC_CAPTURE_LIST_CLASS_VIDEO:397		return "Video";398	case GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE:399		return "VideoEnhance";400	case GUC_CAPTURE_LIST_CLASS_BLITTER:401		return "Blitter";402	case GUC_CAPTURE_LIST_CLASS_GSC_OTHER:403		return "GSC-Other";404	default:405		break;406	}407 408	return "unknown";409}410 411static int412guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid,413		      struct guc_mmio_reg *ptr, u16 num_entries)414{415	u32 i = 0, j = 0;416	const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;417	struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;418	const struct __guc_mmio_reg_descr_group *match;419	struct __guc_mmio_reg_descr_group *matchext;420 421	if (!reglists)422		return -ENODEV;423 424	match = guc_capture_get_one_list(reglists, owner, type, classid);425	if (!match)426		return -ENODATA;427 428	for (i = 0; i < num_entries && i < match->num_regs; ++i) {429		ptr[i].offset = match->list[i].reg.reg;430		ptr[i].value = 0xDEADF00D;431		ptr[i].flags = match->list[i].flags;432		ptr[i].mask = match->list[i].mask;433	}434 435	matchext = guc_capture_get_one_ext_list(extlists, owner, type, classid);436	if (matchext) {437		for (i = match->num_regs, j = 0; i < num_entries &&438		     i < (match->num_regs + matchext->num_regs) &&439			j < matchext->num_regs; ++i, ++j) {440			ptr[i].offset = matchext->extlist[j].reg.reg;441			ptr[i].value = 0xDEADF00D;442			ptr[i].flags = matchext->extlist[j].flags;443			ptr[i].mask = matchext->extlist[j].mask;444		}445	}446	if (i < num_entries)447		guc_dbg(guc, "Got short capture reglist init: %d out %d.\n", i, num_entries);448 449	return 0;450}451 452static int453guc_cap_list_num_regs(struct intel_guc_state_capture *gc, u32 owner, u32 type, u32 classid)454{455	const struct __guc_mmio_reg_descr_group *match;456	struct __guc_mmio_reg_descr_group *matchext;457	int num_regs;458 459	match = guc_capture_get_one_list(gc->reglists, owner, type, classid);460	if (!match)461		return 0;462 463	num_regs = match->num_regs;464 465	matchext = guc_capture_get_one_ext_list(gc->extlists, owner, type, classid);466	if (matchext)467		num_regs += matchext->num_regs;468 469	return num_regs;470}471 472static int473guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,474			size_t *size, bool is_purpose_est)475{476	struct intel_guc_state_capture *gc = guc->capture;477	struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid];478	int num_regs;479 480	if (!gc->reglists) {481		guc_warn(guc, "No capture reglist for this device\n");482		return -ENODEV;483	}484 485	if (cache->is_valid) {486		*size = cache->size;487		return cache->status;488	}489 490	if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&491	    !guc_capture_get_one_list(gc->reglists, owner, type, classid)) {492		if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL)493			guc_warn(guc, "Missing capture reglist: global!\n");494		else495			guc_warn(guc, "Missing capture reglist: %s(%u):%s(%u)!\n",496				 __stringify_type(type), type,497				 __stringify_engclass(classid), classid);498		return -ENODATA;499	}500 501	num_regs = guc_cap_list_num_regs(gc, owner, type, classid);502	/* intentional empty lists can exist depending on hw config */503	if (!num_regs)504		return -ENODATA;505 506	if (size)507		*size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +508				   (num_regs * sizeof(struct guc_mmio_reg)));509 510	return 0;511}512 513int514intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid,515			      size_t *size)516{517	return guc_capture_getlistsize(guc, owner, type, classid, size, false);518}519 520static void guc_capture_create_prealloc_nodes(struct intel_guc *guc);521 522int523intel_guc_capture_getlist(struct intel_guc *guc, u32 owner, u32 type, u32 classid,524			  void **outptr)525{526	struct intel_guc_state_capture *gc = guc->capture;527	struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid];528	struct guc_debug_capture_list *listnode;529	int ret, num_regs;530	u8 *caplist, *tmp;531	size_t size = 0;532 533	if (!gc->reglists)534		return -ENODEV;535 536	if (cache->is_valid) {537		*outptr = cache->ptr;538		return cache->status;539	}540 541	/*542	 * ADS population of input registers is a good543	 * time to pre-allocate cachelist output nodes544	 */545	guc_capture_create_prealloc_nodes(guc);546 547	ret = intel_guc_capture_getlistsize(guc, owner, type, classid, &size);548	if (ret) {549		cache->is_valid = true;550		cache->ptr = NULL;551		cache->size = 0;552		cache->status = ret;553		return ret;554	}555 556	caplist = kzalloc(size, GFP_KERNEL);557	if (!caplist) {558		guc_dbg(guc, "Failed to alloc cached register capture list");559		return -ENOMEM;560	}561 562	/* populate capture list header */563	tmp = caplist;564	num_regs = guc_cap_list_num_regs(guc->capture, owner, type, classid);565	listnode = (struct guc_debug_capture_list *)tmp;566	listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);567 568	/* populate list of register descriptor */569	tmp += sizeof(struct guc_debug_capture_list);570	guc_capture_list_init(guc, owner, type, classid, (struct guc_mmio_reg *)tmp, num_regs);571 572	/* cache this list */573	cache->is_valid = true;574	cache->ptr = caplist;575	cache->size = size;576	cache->status = 0;577 578	*outptr = caplist;579 580	return 0;581}582 583int584intel_guc_capture_getnullheader(struct intel_guc *guc,585				void **outptr, size_t *size)586{587	struct intel_guc_state_capture *gc = guc->capture;588	int tmp = sizeof(u32) * 4;589	void *null_header;590 591	if (gc->ads_null_cache) {592		*outptr = gc->ads_null_cache;593		*size = tmp;594		return 0;595	}596 597	null_header = kzalloc(tmp, GFP_KERNEL);598	if (!null_header) {599		guc_dbg(guc, "Failed to alloc cached register capture null list");600		return -ENOMEM;601	}602 603	gc->ads_null_cache = null_header;604	*outptr = null_header;605	*size = tmp;606 607	return 0;608}609 610static int611guc_capture_output_min_size_est(struct intel_guc *guc)612{613	struct intel_gt *gt = guc_to_gt(guc);614	struct intel_engine_cs *engine;615	enum intel_engine_id id;616	int worst_min_size = 0;617	size_t tmp = 0;618 619	if (!guc->capture)620		return -ENODEV;621 622	/*623	 * If every single engine-instance suffered a failure in quick succession but624	 * were all unrelated, then a burst of multiple error-capture events would dump625	 * registers for every one engine instance, one at a time. In this case, GuC626	 * would even dump the global-registers repeatedly.627	 *628	 * For each engine instance, there would be 1 x guc_state_capture_group_t output629	 * followed by 3 x guc_state_capture_t lists. The latter is how the register630	 * dumps are split across different register types (where the '3' are global vs class631	 * vs instance).632	 */633	for_each_engine(engine, gt, id) {634		worst_min_size += sizeof(struct guc_state_capture_group_header_t) +635					 (3 * sizeof(struct guc_state_capture_header_t));636 637		if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp, true))638			worst_min_size += tmp;639 640		if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS,641					     engine->class, &tmp, true)) {642			worst_min_size += tmp;643		}644		if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE,645					     engine->class, &tmp, true)) {646			worst_min_size += tmp;647		}648	}649 650	return worst_min_size;651}652 653/*654 * Add on a 3x multiplier to allow for multiple back-to-back captures occurring655 * before the i915 can read the data out and process it656 */657#define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3658 659static void check_guc_capture_size(struct intel_guc *guc)660{661	int min_size = guc_capture_output_min_size_est(guc);662	int spare_size = min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;663	u32 buffer_size = intel_guc_log_section_size_capture(&guc->log);664 665	/*666	 * NOTE: min_size is much smaller than the capture region allocation (DG2: <80K vs 1MB)667	 * Additionally, its based on space needed to fit all engines getting reset at once668	 * within the same G2H handler task slot. This is very unlikely. However, if GuC really669	 * does run out of space for whatever reason, we will see an separate warning message670	 * when processing the G2H event capture-notification, search for:671	 * INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE.672	 */673	if (min_size < 0)674		guc_warn(guc, "Failed to calculate error state capture buffer minimum size: %d!\n",675			 min_size);676	else if (min_size > buffer_size)677		guc_warn(guc, "Error state capture buffer maybe small: %d < %d\n",678			 buffer_size, min_size);679	else if (spare_size > buffer_size)680		guc_dbg(guc, "Error state capture buffer lacks spare size: %d < %d (min = %d)\n",681			buffer_size, spare_size, min_size);682}683 684/*685 * KMD Init time flows:686 * --------------------687 *     --> alloc A: GuC input capture regs lists (registered to GuC via ADS).688 *                  intel_guc_ads acquires the register lists by calling689 *                  intel_guc_capture_list_size and intel_guc_capture_list_get 'n' times,690 *                  where n = 1 for global-reg-list +691 *                            num_engine_classes for class-reg-list +692 *                            num_engine_classes for instance-reg-list693 *                               (since all instances of the same engine-class type694 *                                have an identical engine-instance register-list).695 *                  ADS module also calls separately for PF vs VF.696 *697 *     --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))698 *                  Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small)699 *                  Note2: 'x 3' to hold multiple capture groups700 *701 * GUC Runtime notify capture:702 * --------------------------703 *     --> G2H STATE_CAPTURE_NOTIFICATION704 *                   L--> intel_guc_capture_process705 *                           L--> Loop through B (head..tail) and for each engine instance's706 *                                err-state-captured register-list we find, we alloc 'C':707 *      --> alloc C: A capture-output-node structure that includes misc capture info along708 *                   with 3 register list dumps (global, engine-class and engine-instance)709 *                   This node is created from a pre-allocated list of blank nodes in710 *                   guc->capture->cachelist and populated with the error-capture711 *                   data from GuC and then it's added into guc->capture->outlist linked712 *                   list. This list is used for matchup and printout by i915_gpu_coredump713 *                   and err_print_gt, (when user invokes the error capture sysfs).714 *715 * GUC --> notify context reset:716 * -----------------------------717 *     --> G2H CONTEXT RESET718 *                   L--> guc_handle_context_reset --> i915_capture_error_state719 *                          L--> i915_gpu_coredump(..IS_GUC_CAPTURE) --> gt_record_engines720 *                               --> capture_engine(..IS_GUC_CAPTURE)721 *                               L--> intel_guc_capture_get_matching_node is where722 *                                    detach C from internal linked list and add it into723 *                                    intel_engine_coredump struct (if the context and724 *                                    engine of the event notification matches a node725 *                                    in the link list).726 *727 * User Sysfs / Debugfs728 * --------------------729 *      --> i915_gpu_coredump_copy_to_buffer->730 *                   L--> err_print_to_sgl --> err_print_gt731 *                        L--> error_print_guc_captures732 *                             L--> intel_guc_capture_print_node prints the733 *                                  register lists values of the attached node734 *                                  on the error-engine-dump being reported.735 *                   L--> i915_reset_error_state ... -->__i915_gpu_coredump_free736 *                        L--> ... cleanup_gt -->737 *                             L--> intel_guc_capture_free_node returns the738 *                                  capture-output-node back to the internal739 *                                  cachelist for reuse.740 *741 */742 743static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)744{745	if (buf->wr >= buf->rd)746		return (buf->wr - buf->rd);747	return (buf->size - buf->rd) + buf->wr;748}749 750static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)751{752	if (buf->rd > buf->wr)753		return (buf->size - buf->rd);754	return (buf->wr - buf->rd);755}756 757/*758 * GuC's error-capture output is a ring buffer populated in a byte-stream fashion:759 *760 * The GuC Log buffer region for error-capture is managed like a ring buffer.761 * The GuC firmware dumps error capture logs into this ring in a byte-stream flow.762 * Additionally, as per the current and foreseeable future, all packed error-763 * capture output structures are dword aligned.764 *765 * That said, if the GuC firmware is in the midst of writing a structure that is larger766 * than one dword but the tail end of the err-capture buffer-region has lesser space left,767 * we would need to extract that structure one dword at a time straddled across the end,768 * onto the start of the ring.769 *770 * Below function, guc_capture_log_remove_dw is a helper for that. All callers of this771 * function would typically do a straight-up memcpy from the ring contents and will only772 * call this helper if their structure-extraction is straddling across the end of the773 * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease774 * scalability for future expansion of output data types without requiring a redesign775 * of the flow controls.776 */777static int778guc_capture_log_remove_dw(struct intel_guc *guc, struct __guc_capture_bufstate *buf,779			  u32 *dw)780{781	int tries = 2;782	int avail = 0;783	u32 *src_data;784 785	if (!guc_capture_buf_cnt(buf))786		return 0;787 788	while (tries--) {789		avail = guc_capture_buf_cnt_to_end(buf);790		if (avail >= sizeof(u32)) {791			src_data = (u32 *)(buf->data + buf->rd);792			*dw = *src_data;793			buf->rd += 4;794			return 4;795		}796		if (avail)797			guc_dbg(guc, "Register capture log not dword aligned, skipping.\n");798		buf->rd = 0;799	}800 801	return 0;802}803 804static bool805guc_capture_data_extracted(struct __guc_capture_bufstate *b,806			   int size, void *dest)807{808	if (guc_capture_buf_cnt_to_end(b) >= size) {809		memcpy(dest, (b->data + b->rd), size);810		b->rd += size;811		return true;812	}813	return false;814}815 816static int817guc_capture_log_get_group_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,818			      struct guc_state_capture_group_header_t *ghdr)819{820	int read = 0;821	int fullsize = sizeof(struct guc_state_capture_group_header_t);822 823	if (fullsize > guc_capture_buf_cnt(buf))824		return -1;825 826	if (guc_capture_data_extracted(buf, fullsize, (void *)ghdr))827		return 0;828 829	read += guc_capture_log_remove_dw(guc, buf, &ghdr->owner);830	read += guc_capture_log_remove_dw(guc, buf, &ghdr->info);831	if (read != fullsize)832		return -1;833 834	return 0;835}836 837static int838guc_capture_log_get_data_hdr(struct intel_guc *guc, struct __guc_capture_bufstate *buf,839			     struct guc_state_capture_header_t *hdr)840{841	int read = 0;842	int fullsize = sizeof(struct guc_state_capture_header_t);843 844	if (fullsize > guc_capture_buf_cnt(buf))845		return -1;846 847	if (guc_capture_data_extracted(buf, fullsize, (void *)hdr))848		return 0;849 850	read += guc_capture_log_remove_dw(guc, buf, &hdr->owner);851	read += guc_capture_log_remove_dw(guc, buf, &hdr->info);852	read += guc_capture_log_remove_dw(guc, buf, &hdr->lrca);853	read += guc_capture_log_remove_dw(guc, buf, &hdr->guc_id);854	read += guc_capture_log_remove_dw(guc, buf, &hdr->num_mmios);855	if (read != fullsize)856		return -1;857 858	return 0;859}860 861static int862guc_capture_log_get_register(struct intel_guc *guc, struct __guc_capture_bufstate *buf,863			     struct guc_mmio_reg *reg)864{865	int read = 0;866	int fullsize = sizeof(struct guc_mmio_reg);867 868	if (fullsize > guc_capture_buf_cnt(buf))869		return -1;870 871	if (guc_capture_data_extracted(buf, fullsize, (void *)reg))872		return 0;873 874	read += guc_capture_log_remove_dw(guc, buf, &reg->offset);875	read += guc_capture_log_remove_dw(guc, buf, &reg->value);876	read += guc_capture_log_remove_dw(guc, buf, &reg->flags);877	read += guc_capture_log_remove_dw(guc, buf, &reg->mask);878	if (read != fullsize)879		return -1;880 881	return 0;882}883 884static void885guc_capture_delete_one_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)886{887	int i;888 889	for (i = 0; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i)890		kfree(node->reginfo[i].regs);891	list_del(&node->link);892	kfree(node);893}894 895static void896guc_capture_delete_prealloc_nodes(struct intel_guc *guc)897{898	struct __guc_capture_parsed_output *n, *ntmp;899 900	/*901	 * NOTE: At the end of driver operation, we must assume that we902	 * have prealloc nodes in both the cachelist as well as outlist903	 * if unclaimed error capture events occurred prior to shutdown.904	 */905	list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link)906		guc_capture_delete_one_node(guc, n);907 908	list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link)909		guc_capture_delete_one_node(guc, n);910}911 912static void913guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node,914			     struct list_head *list)915{916	list_add_tail(&node->link, list);917}918 919static void920guc_capture_add_node_to_outlist(struct intel_guc_state_capture *gc,921				struct __guc_capture_parsed_output *node)922{923	guc_capture_add_node_to_list(node, &gc->outlist);924}925 926static void927guc_capture_add_node_to_cachelist(struct intel_guc_state_capture *gc,928				  struct __guc_capture_parsed_output *node)929{930	guc_capture_add_node_to_list(node, &gc->cachelist);931}932 933static void934guc_capture_init_node(struct intel_guc *guc, struct __guc_capture_parsed_output *node)935{936	struct guc_mmio_reg *tmp[GUC_CAPTURE_LIST_TYPE_MAX];937	int i;938 939	for (i = 0; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {940		tmp[i] = node->reginfo[i].regs;941		memset(tmp[i], 0, sizeof(struct guc_mmio_reg) *942		       guc->capture->max_mmio_per_node);943	}944	memset(node, 0, sizeof(*node));945	for (i = 0; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i)946		node->reginfo[i].regs = tmp[i];947 948	INIT_LIST_HEAD(&node->link);949}950 951static struct __guc_capture_parsed_output *952guc_capture_get_prealloc_node(struct intel_guc *guc)953{954	struct __guc_capture_parsed_output *found = NULL;955 956	if (!list_empty(&guc->capture->cachelist)) {957		struct __guc_capture_parsed_output *n, *ntmp;958 959		/* get first avail node from the cache list */960		list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) {961			found = n;962			list_del(&n->link);963			break;964		}965	} else {966		struct __guc_capture_parsed_output *n, *ntmp;967 968		/* traverse down and steal back the oldest node already allocated */969		list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) {970			found = n;971		}972		if (found)973			list_del(&found->link);974	}975	if (found)976		guc_capture_init_node(guc, found);977 978	return found;979}980 981static struct __guc_capture_parsed_output *982guc_capture_alloc_one_node(struct intel_guc *guc)983{984	struct __guc_capture_parsed_output *new;985	int i;986 987	new = kzalloc(sizeof(*new), GFP_KERNEL);988	if (!new)989		return NULL;990 991	for (i = 0; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {992		new->reginfo[i].regs = kcalloc(guc->capture->max_mmio_per_node,993					       sizeof(struct guc_mmio_reg), GFP_KERNEL);994		if (!new->reginfo[i].regs) {995			while (i)996				kfree(new->reginfo[--i].regs);997			kfree(new);998			return NULL;999		}1000	}1001	guc_capture_init_node(guc, new);1002 1003	return new;1004}1005 1006static struct __guc_capture_parsed_output *1007guc_capture_clone_node(struct intel_guc *guc, struct __guc_capture_parsed_output *original,1008		       u32 keep_reglist_mask)1009{1010	struct __guc_capture_parsed_output *new;1011	int i;1012 1013	new = guc_capture_get_prealloc_node(guc);1014	if (!new)1015		return NULL;1016	if (!original)1017		return new;1018 1019	new->is_partial = original->is_partial;1020 1021	/* copy reg-lists that we want to clone */1022	for (i = 0; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {1023		if (keep_reglist_mask & BIT(i)) {1024			GEM_BUG_ON(original->reginfo[i].num_regs  >1025				   guc->capture->max_mmio_per_node);1026 1027			memcpy(new->reginfo[i].regs, original->reginfo[i].regs,1028			       original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg));1029 1030			new->reginfo[i].num_regs = original->reginfo[i].num_regs;1031			new->reginfo[i].vfid  = original->reginfo[i].vfid;1032 1033			if (i == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS) {1034				new->eng_class = original->eng_class;1035			} else if (i == GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE) {1036				new->eng_inst = original->eng_inst;1037				new->guc_id = original->guc_id;1038				new->lrca = original->lrca;1039			}1040		}1041	}1042 1043	return new;1044}1045 1046static void1047__guc_capture_create_prealloc_nodes(struct intel_guc *guc)1048{1049	struct __guc_capture_parsed_output *node = NULL;1050	int i;1051 1052	for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) {1053		node = guc_capture_alloc_one_node(guc);1054		if (!node) {1055			guc_warn(guc, "Register capture pre-alloc-cache failure\n");1056			/* dont free the priors, use what we got and cleanup at shutdown */1057			return;1058		}1059		guc_capture_add_node_to_cachelist(guc->capture, node);1060	}1061}1062 1063static int1064guc_get_max_reglist_count(struct intel_guc *guc)1065{1066	int i, j, k, tmp, maxregcount = 0;1067 1068	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {1069		for (j = 0; j < GUC_CAPTURE_LIST_TYPE_MAX; ++j) {1070			for (k = 0; k < GUC_MAX_ENGINE_CLASSES; ++k) {1071				if (j == GUC_CAPTURE_LIST_TYPE_GLOBAL && k > 0)1072					continue;1073 1074				tmp = guc_cap_list_num_regs(guc->capture, i, j, k);1075				if (tmp > maxregcount)1076					maxregcount = tmp;1077			}1078		}1079	}1080	if (!maxregcount)1081		maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS;1082 1083	return maxregcount;1084}1085 1086static void1087guc_capture_create_prealloc_nodes(struct intel_guc *guc)1088{1089	/* skip if we've already done the pre-alloc */1090	if (guc->capture->max_mmio_per_node)1091		return;1092 1093	guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc);1094	__guc_capture_create_prealloc_nodes(guc);1095}1096 1097static int1098guc_capture_extract_reglists(struct intel_guc *guc, struct __guc_capture_bufstate *buf)1099{1100	struct guc_state_capture_group_header_t ghdr = {};1101	struct guc_state_capture_header_t hdr = {};1102	struct __guc_capture_parsed_output *node = NULL;1103	struct guc_mmio_reg *regs = NULL;1104	int i, numlists, numregs, ret = 0;1105	enum guc_capture_type datatype;1106	struct guc_mmio_reg tmp;1107	bool is_partial = false;1108 1109	i = guc_capture_buf_cnt(buf);1110	if (!i)1111		return -ENODATA;1112	if (i % sizeof(u32)) {1113		guc_warn(guc, "Got mis-aligned register capture entries\n");1114		ret = -EIO;1115		goto bailout;1116	}1117 1118	/* first get the capture group header */1119	if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {1120		ret = -EIO;1121		goto bailout;1122	}1123	/*1124	 * we would typically expect a layout as below where n would be expected to be1125	 * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine1126	 * instances being reset together.1127	 * ____________________________________________1128	 * | Capture Group                            |1129	 * | ________________________________________ |1130	 * | | Capture Group Header:                | |1131	 * | |  - num_captures = 5                  | |1132	 * | |______________________________________| |1133	 * | ________________________________________ |1134	 * | | Capture1:                            | |1135	 * | |  Hdr: GLOBAL, numregs=a              | |1136	 * | | ____________________________________ | |1137	 * | | | Reglist                          | | |1138	 * | | | - reg1, reg2, ... rega           | | |1139	 * | | |__________________________________| | |1140	 * | |______________________________________| |1141	 * | ________________________________________ |1142	 * | | Capture2:                            | |1143	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=b| |1144	 * | | ____________________________________ | |1145	 * | | | Reglist                          | | |1146	 * | | | - reg1, reg2, ... regb           | | |1147	 * | | |__________________________________| | |1148	 * | |______________________________________| |1149	 * | ________________________________________ |1150	 * | | Capture3:                            | |1151	 * | |  Hdr: INSTANCE=RCS, numregs=c        | |1152	 * | | ____________________________________ | |1153	 * | | | Reglist                          | | |1154	 * | | | - reg1, reg2, ... regc           | | |1155	 * | | |__________________________________| | |1156	 * | |______________________________________| |1157	 * | ________________________________________ |1158	 * | | Capture4:                            | |1159	 * | |  Hdr: CLASS=RENDER/COMPUTE, numregs=d| |1160	 * | | ____________________________________ | |1161	 * | | | Reglist                          | | |1162	 * | | | - reg1, reg2, ... regd           | | |1163	 * | | |__________________________________| | |1164	 * | |______________________________________| |1165	 * | ________________________________________ |1166	 * | | Capture5:                            | |1167	 * | |  Hdr: INSTANCE=CCS0, numregs=e       | |1168	 * | | ____________________________________ | |1169	 * | | | Reglist                          | | |1170	 * | | | - reg1, reg2, ... rege           | | |1171	 * | | |__________________________________| | |1172	 * | |______________________________________| |1173	 * |__________________________________________|1174	 */1175	is_partial = FIELD_GET(CAP_GRP_HDR_CAPTURE_TYPE, ghdr.info);1176	numlists = FIELD_GET(CAP_GRP_HDR_NUM_CAPTURES, ghdr.info);1177 1178	while (numlists--) {1179		if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {1180			ret = -EIO;1181			break;1182		}1183 1184		datatype = FIELD_GET(CAP_HDR_CAPTURE_TYPE, hdr.info);1185		if (datatype > GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE) {1186			/* unknown capture type - skip over to next capture set */1187			numregs = FIELD_GET(CAP_HDR_NUM_MMIOS, hdr.num_mmios);1188			while (numregs--) {1189				if (guc_capture_log_get_register(guc, buf, &tmp)) {1190					ret = -EIO;1191					break;1192				}1193			}1194			continue;1195		} else if (node) {1196			/*1197			 * Based on the current capture type and what we have so far,1198			 * decide if we should add the current node into the internal1199			 * linked list for match-up when i915_gpu_coredump calls later1200			 * (and alloc a blank node for the next set of reglists)1201			 * or continue with the same node or clone the current node1202			 * but only retain the global or class registers (such as the1203			 * case of dependent engine resets).1204			 */1205			if (datatype == GUC_CAPTURE_LIST_TYPE_GLOBAL) {1206				guc_capture_add_node_to_outlist(guc->capture, node);1207				node = NULL;1208			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS &&1209				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS].num_regs) {1210				/* Add to list, clone node and duplicate global list */1211				guc_capture_add_node_to_outlist(guc->capture, node);1212				node = guc_capture_clone_node(guc, node,1213							      GCAP_PARSED_REGLIST_INDEX_GLOBAL);1214			} else if (datatype == GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE &&1215				   node->reginfo[GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE].num_regs) {1216				/* Add to list, clone node and duplicate global + class lists */1217				guc_capture_add_node_to_outlist(guc->capture, node);1218				node = guc_capture_clone_node(guc, node,1219							      (GCAP_PARSED_REGLIST_INDEX_GLOBAL |1220							      GCAP_PARSED_REGLIST_INDEX_ENGCLASS));1221			}1222		}1223 1224		if (!node) {1225			node = guc_capture_get_prealloc_node(guc);1226			if (!node) {1227				ret = -ENOMEM;1228				break;1229			}1230			if (datatype != GUC_CAPTURE_LIST_TYPE_GLOBAL)1231				guc_dbg(guc, "Register capture missing global dump: %08x!\n",1232					datatype);1233		}1234		node->is_partial = is_partial;1235		node->reginfo[datatype].vfid = FIELD_GET(CAP_HDR_CAPTURE_VFID, hdr.owner);1236		switch (datatype) {1237		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:1238			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);1239			node->eng_inst = FIELD_GET(CAP_HDR_ENGINE_INSTANCE, hdr.info);1240			node->lrca = hdr.lrca;1241			node->guc_id = hdr.guc_id;1242			break;1243		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:1244			node->eng_class = FIELD_GET(CAP_HDR_ENGINE_CLASS, hdr.info);1245			break;1246		default:1247			break;1248		}1249 1250		numregs = FIELD_GET(CAP_HDR_NUM_MMIOS, hdr.num_mmios);1251		if (numregs > guc->capture->max_mmio_per_node) {1252			guc_dbg(guc, "Register capture list extraction clipped by prealloc!\n");1253			numregs = guc->capture->max_mmio_per_node;1254		}1255		node->reginfo[datatype].num_regs = numregs;1256		regs = node->reginfo[datatype].regs;1257		i = 0;1258		while (numregs--) {1259			if (guc_capture_log_get_register(guc, buf, &regs[i++])) {1260				ret = -EIO;1261				break;1262			}1263		}1264	}1265 1266bailout:1267	if (node) {1268		/* If we have data, add to linked list for match-up when i915_gpu_coredump calls */1269		for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {1270			if (node->reginfo[i].regs) {1271				guc_capture_add_node_to_outlist(guc->capture, node);1272				node = NULL;1273				break;1274			}1275		}1276		if (node) /* else return it back to cache list */1277			guc_capture_add_node_to_cachelist(guc->capture, node);1278	}1279	return ret;1280}1281 1282static int __guc_capture_flushlog_complete(struct intel_guc *guc)1283{1284	u32 action[] = {1285		INTEL_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE,1286		GUC_CAPTURE_LOG_BUFFER1287	};1288 1289	return intel_guc_send_nb(guc, action, ARRAY_SIZE(action), 0);1290 1291}1292 1293static void __guc_capture_process_output(struct intel_guc *guc)1294{1295	unsigned int buffer_size, read_offset, write_offset, full_count;1296	struct intel_uc *uc = container_of(guc, typeof(*uc), guc);1297	struct guc_log_buffer_state log_buf_state_local;1298	struct guc_log_buffer_state *log_buf_state;1299	struct __guc_capture_bufstate buf;1300	void *src_data = NULL;1301	bool new_overflow;1302	int ret;1303 1304	log_buf_state = guc->log.buf_addr +1305			(sizeof(struct guc_log_buffer_state) * GUC_CAPTURE_LOG_BUFFER);1306	src_data = guc->log.buf_addr +1307		   intel_guc_get_log_buffer_offset(&guc->log, GUC_CAPTURE_LOG_BUFFER);1308 1309	/*1310	 * Make a copy of the state structure, inside GuC log buffer1311	 * (which is uncached mapped), on the stack to avoid reading1312	 * from it multiple times.1313	 */1314	memcpy(&log_buf_state_local, log_buf_state, sizeof(struct guc_log_buffer_state));1315	buffer_size = intel_guc_get_log_buffer_size(&guc->log, GUC_CAPTURE_LOG_BUFFER);1316	read_offset = log_buf_state_local.read_ptr;1317	write_offset = log_buf_state_local.sampled_write_ptr;1318	full_count = log_buf_state_local.buffer_full_cnt;1319 1320	/* Bookkeeping stuff */1321	guc->log.stats[GUC_CAPTURE_LOG_BUFFER].flush += log_buf_state_local.flush_to_file;1322	new_overflow = intel_guc_check_log_buf_overflow(&guc->log, GUC_CAPTURE_LOG_BUFFER,1323							full_count);1324 1325	/* Now copy the actual logs. */1326	if (unlikely(new_overflow)) {1327		/* copy the whole buffer in case of overflow */1328		read_offset = 0;1329		write_offset = buffer_size;1330	} else if (unlikely((read_offset > buffer_size) ||1331			(write_offset > buffer_size))) {1332		guc_err(guc, "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n",1333			read_offset, buffer_size);1334		/* copy whole buffer as offsets are unreliable */1335		read_offset = 0;1336		write_offset = buffer_size;1337	}1338 1339	buf.size = buffer_size;1340	buf.rd = read_offset;1341	buf.wr = write_offset;1342	buf.data = src_data;1343 1344	if (!uc->reset_in_progress) {1345		do {1346			ret = guc_capture_extract_reglists(guc, &buf);1347		} while (ret >= 0);1348	}1349 1350	/* Update the state of log buffer err-cap state */1351	log_buf_state->read_ptr = write_offset;1352	log_buf_state->flush_to_file = 0;1353	__guc_capture_flushlog_complete(guc);1354}1355 1356#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)1357 1358static const char *1359guc_capture_reg_to_str(const struct intel_guc *guc, u32 owner, u32 type,1360		       u32 class, u32 id, u32 offset, u32 *is_ext)1361{1362	const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;1363	struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;1364	const struct __guc_mmio_reg_descr_group *match;1365	struct __guc_mmio_reg_descr_group *matchext;1366	int j;1367 1368	*is_ext = 0;1369	if (!reglists)1370		return NULL;1371 1372	match = guc_capture_get_one_list(reglists, owner, type, id);1373	if (!match)1374		return NULL;1375 1376	for (j = 0; j < match->num_regs; ++j) {1377		if (offset == match->list[j].reg.reg)1378			return match->list[j].regname;1379	}1380	if (extlists) {1381		matchext = guc_capture_get_one_ext_list(extlists, owner, type, id);1382		if (!matchext)1383			return NULL;1384		for (j = 0; j < matchext->num_regs; ++j) {1385			if (offset == matchext->extlist[j].reg.reg) {1386				*is_ext = 1;1387				return matchext->extlist[j].regname;1388			}1389		}1390	}1391 1392	return NULL;1393}1394 1395#define GCAP_PRINT_INTEL_ENG_INFO(ebuf, eng) \1396	do { \1397		i915_error_printf(ebuf, "    i915-Eng-Name: %s command stream\n", \1398				  (eng)->name); \1399		i915_error_printf(ebuf, "    i915-Eng-Inst-Class: 0x%02x\n", (eng)->class); \1400		i915_error_printf(ebuf, "    i915-Eng-Inst-Id: 0x%02x\n", (eng)->instance); \1401		i915_error_printf(ebuf, "    i915-Eng-LogicalMask: 0x%08x\n", \1402				  (eng)->logical_mask); \1403	} while (0)1404 1405#define GCAP_PRINT_GUC_INST_INFO(ebuf, node) \1406	do { \1407		i915_error_printf(ebuf, "    GuC-Engine-Inst-Id: 0x%08x\n", \1408				  (node)->eng_inst); \1409		i915_error_printf(ebuf, "    GuC-Context-Id: 0x%08x\n", (node)->guc_id); \1410		i915_error_printf(ebuf, "    LRCA: 0x%08x\n", (node)->lrca); \1411	} while (0)1412 1413int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,1414					const struct intel_engine_coredump *ee)1415{1416	const char *grptype[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {1417		"full-capture",1418		"partial-capture"1419	};1420	const char *datatype[GUC_CAPTURE_LIST_TYPE_MAX] = {1421		"Global",1422		"Engine-Class",1423		"Engine-Instance"1424	};1425	struct intel_guc_state_capture *cap;1426	struct __guc_capture_parsed_output *node;1427	struct intel_engine_cs *eng;1428	struct guc_mmio_reg *regs;1429	struct intel_guc *guc;1430	const char *str;1431	int numregs, i, j;1432	u32 is_ext;1433 1434	if (!ebuf || !ee)1435		return -EINVAL;1436	cap = ee->guc_capture;1437	if (!cap || !ee->engine)1438		return -ENODEV;1439 1440	guc = gt_to_guc(ee->engine->gt);1441 1442	i915_error_printf(ebuf, "global --- GuC Error Capture on %s command stream:\n",1443			  ee->engine->name);1444 1445	node = ee->guc_capture_node;1446	if (!node) {1447		i915_error_printf(ebuf, "  No matching ee-node\n");1448		return 0;1449	}1450 1451	i915_error_printf(ebuf, "Coverage:  %s\n", grptype[node->is_partial]);1452 1453	for (i = GUC_CAPTURE_LIST_TYPE_GLOBAL; i < GUC_CAPTURE_LIST_TYPE_MAX; ++i) {1454		i915_error_printf(ebuf, "  RegListType: %s\n",1455				  datatype[i % GUC_CAPTURE_LIST_TYPE_MAX]);1456		i915_error_printf(ebuf, "    Owner-Id: %d\n", node->reginfo[i].vfid);1457 1458		switch (i) {1459		case GUC_CAPTURE_LIST_TYPE_GLOBAL:1460		default:1461			break;1462		case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS:1463			i915_error_printf(ebuf, "    GuC-Eng-Class: %d\n", node->eng_class);1464			i915_error_printf(ebuf, "    i915-Eng-Class: %d\n",1465					  guc_class_to_engine_class(node->eng_class));1466			break;1467		case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE:1468			eng = intel_guc_lookup_engine(guc, node->eng_class, node->eng_inst);1469			if (eng)1470				GCAP_PRINT_INTEL_ENG_INFO(ebuf, eng);1471			else1472				i915_error_printf(ebuf, "    i915-Eng-Lookup Fail!\n");1473			GCAP_PRINT_GUC_INST_INFO(ebuf, node);1474			break;1475		}1476 1477		numregs = node->reginfo[i].num_regs;1478		i915_error_printf(ebuf, "    NumRegs: %d\n", numregs);1479		j = 0;1480		while (numregs--) {1481			regs = node->reginfo[i].regs;1482			str = guc_capture_reg_to_str(guc, GUC_CAPTURE_LIST_INDEX_PF, i,1483						     node->eng_class, 0, regs[j].offset, &is_ext);1484			if (!str)1485				i915_error_printf(ebuf, "      REG-0x%08x", regs[j].offset);1486			else1487				i915_error_printf(ebuf, "      %s", str);1488			if (is_ext)1489				i915_error_printf(ebuf, "[%ld][%ld]",1490					FIELD_GET(GUC_REGSET_STEERING_GROUP, regs[j].flags),1491					FIELD_GET(GUC_REGSET_STEERING_INSTANCE, regs[j].flags));1492			i915_error_printf(ebuf, ":  0x%08x\n", regs[j].value);1493			++j;1494		}1495	}1496	return 0;1497}1498 1499#endif //CONFIG_DRM_I915_CAPTURE_ERROR1500 1501static void guc_capture_find_ecode(struct intel_engine_coredump *ee)1502{1503	struct gcap_reg_list_info *reginfo;1504	struct guc_mmio_reg *regs;1505	i915_reg_t reg_ipehr = RING_IPEHR(0);1506	i915_reg_t reg_instdone = RING_INSTDONE(0);1507	int i;1508 1509	if (!ee->guc_capture_node)1510		return;1511 1512	reginfo = ee->guc_capture_node->reginfo + GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE;1513	regs = reginfo->regs;1514	for (i = 0; i < reginfo->num_regs; i++) {1515		if (regs[i].offset == reg_ipehr.reg)1516			ee->ipehr = regs[i].value;1517		else if (regs[i].offset == reg_instdone.reg)1518			ee->instdone.instdone = regs[i].value;1519	}1520}1521 1522void intel_guc_capture_free_node(struct intel_engine_coredump *ee)1523{1524	if (!ee || !ee->guc_capture_node)1525		return;1526 1527	guc_capture_add_node_to_cachelist(ee->guc_capture, ee->guc_capture_node);1528	ee->guc_capture = NULL;1529	ee->guc_capture_node = NULL;1530}1531 1532bool intel_guc_capture_is_matching_engine(struct intel_gt *gt,1533					  struct intel_context *ce,1534					  struct intel_engine_cs *engine)1535{1536	struct __guc_capture_parsed_output *n;1537	struct intel_guc *guc;1538 1539	if (!gt || !ce || !engine)1540		return false;1541 1542	guc = gt_to_guc(gt);1543	if (!guc->capture)1544		return false;1545 1546	/*1547	 * Look for a matching GuC reported error capture node from1548	 * the internal output link-list based on lrca, guc-id and engine1549	 * identification.1550	 */1551	list_for_each_entry(n, &guc->capture->outlist, link) {1552		if (n->eng_inst == GUC_ID_TO_ENGINE_INSTANCE(engine->guc_id) &&1553		    n->eng_class == GUC_ID_TO_ENGINE_CLASS(engine->guc_id) &&1554		    n->guc_id == ce->guc_id.id &&1555		    (n->lrca & CTX_GTT_ADDRESS_MASK) == (ce->lrc.lrca & CTX_GTT_ADDRESS_MASK))1556			return true;1557	}1558 1559	return false;1560}1561 1562void intel_guc_capture_get_matching_node(struct intel_gt *gt,1563					 struct intel_engine_coredump *ee,1564					 struct intel_context *ce)1565{1566	struct __guc_capture_parsed_output *n, *ntmp;1567	struct intel_guc *guc;1568 1569	if (!gt || !ee || !ce)1570		return;1571 1572	guc = gt_to_guc(gt);1573	if (!guc->capture)1574		return;1575 1576	GEM_BUG_ON(ee->guc_capture_node);1577 1578	/*1579	 * Look for a matching GuC reported error capture node from1580	 * the internal output link-list based on lrca, guc-id and engine1581	 * identification.1582	 */1583	list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) {1584		if (n->eng_inst == GUC_ID_TO_ENGINE_INSTANCE(ee->engine->guc_id) &&1585		    n->eng_class == GUC_ID_TO_ENGINE_CLASS(ee->engine->guc_id) &&1586		    n->guc_id == ce->guc_id.id &&1587		    (n->lrca & CTX_GTT_ADDRESS_MASK) == (ce->lrc.lrca & CTX_GTT_ADDRESS_MASK)) {1588			list_del(&n->link);1589			ee->guc_capture_node = n;1590			ee->guc_capture = guc->capture;1591			guc_capture_find_ecode(ee);1592			return;1593		}1594	}1595 1596	guc_warn(guc, "No register capture node found for 0x%04X / 0x%08X\n",1597		 ce->guc_id.id, ce->lrc.lrca);1598}1599 1600void intel_guc_capture_process(struct intel_guc *guc)1601{1602	if (guc->capture)1603		__guc_capture_process_output(guc);1604}1605 1606static void1607guc_capture_free_ads_cache(struct intel_guc_state_capture *gc)1608{1609	int i, j, k;1610	struct __guc_capture_ads_cache *cache;1611 1612	for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {1613		for (j = 0; j < GUC_CAPTURE_LIST_TYPE_MAX; ++j) {1614			for (k = 0; k < GUC_MAX_ENGINE_CLASSES; ++k) {1615				cache = &gc->ads_cache[i][j][k];1616				if (cache->is_valid)1617					kfree(cache->ptr);1618			}1619		}1620	}1621	kfree(gc->ads_null_cache);1622}1623 1624void intel_guc_capture_destroy(struct intel_guc *guc)1625{1626	if (!guc->capture)1627		return;1628 1629	guc_capture_free_ads_cache(guc->capture);1630 1631	guc_capture_delete_prealloc_nodes(guc);1632 1633	guc_capture_free_extlists(guc->capture->extlists);1634	kfree(guc->capture->extlists);1635 1636	kfree(guc->capture);1637	guc->capture = NULL;1638}1639 1640int intel_guc_capture_init(struct intel_guc *guc)1641{1642	guc->capture = kzalloc(sizeof(*guc->capture), GFP_KERNEL);1643	if (!guc->capture)1644		return -ENOMEM;1645 1646	guc->capture->reglists = guc_capture_get_device_reglist(guc);1647 1648	INIT_LIST_HEAD(&guc->capture->outlist);1649	INIT_LIST_HEAD(&guc->capture->cachelist);1650 1651	check_guc_capture_size(guc);1652 1653	return 0;1654}1655