19c8c7a7eSZhanjun Dong // SPDX-License-Identifier: MIT
29c8c7a7eSZhanjun Dong /*
39c8c7a7eSZhanjun Dong * Copyright © 2021-2024 Intel Corporation
49c8c7a7eSZhanjun Dong */
59c8c7a7eSZhanjun Dong
69c8c7a7eSZhanjun Dong #include <linux/types.h>
79c8c7a7eSZhanjun Dong
89c8c7a7eSZhanjun Dong #include <drm/drm_managed.h>
99c8c7a7eSZhanjun Dong #include <drm/drm_print.h>
109c8c7a7eSZhanjun Dong
119c8c7a7eSZhanjun Dong #include "abi/guc_actions_abi.h"
129c8c7a7eSZhanjun Dong #include "abi/guc_capture_abi.h"
138bfc4963SZhanjun Dong #include "abi/guc_log_abi.h"
149c8c7a7eSZhanjun Dong #include "regs/xe_engine_regs.h"
159c8c7a7eSZhanjun Dong #include "regs/xe_gt_regs.h"
169c8c7a7eSZhanjun Dong #include "regs/xe_guc_regs.h"
179c8c7a7eSZhanjun Dong #include "regs/xe_regs.h"
189c8c7a7eSZhanjun Dong
199c8c7a7eSZhanjun Dong #include "xe_bo.h"
209c8c7a7eSZhanjun Dong #include "xe_device.h"
219c8c7a7eSZhanjun Dong #include "xe_exec_queue_types.h"
229c8c7a7eSZhanjun Dong #include "xe_gt.h"
239c8c7a7eSZhanjun Dong #include "xe_gt_mcr.h"
249c8c7a7eSZhanjun Dong #include "xe_gt_printk.h"
259c8c7a7eSZhanjun Dong #include "xe_guc.h"
2684d15f42SZhanjun Dong #include "xe_guc_ads.h"
279c8c7a7eSZhanjun Dong #include "xe_guc_capture.h"
289c8c7a7eSZhanjun Dong #include "xe_guc_capture_types.h"
299c8c7a7eSZhanjun Dong #include "xe_guc_ct.h"
30ecb63364SZhanjun Dong #include "xe_guc_exec_queue_types.h"
319c8c7a7eSZhanjun Dong #include "xe_guc_log.h"
32ecb63364SZhanjun Dong #include "xe_guc_submit_types.h"
339c8c7a7eSZhanjun Dong #include "xe_guc_submit.h"
349c8c7a7eSZhanjun Dong #include "xe_hw_engine_types.h"
35ecb63364SZhanjun Dong #include "xe_hw_engine.h"
36ecb63364SZhanjun Dong #include "xe_lrc.h"
379c8c7a7eSZhanjun Dong #include "xe_macros.h"
389c8c7a7eSZhanjun Dong #include "xe_map.h"
39ecb63364SZhanjun Dong #include "xe_mmio.h"
40ecb63364SZhanjun Dong #include "xe_sched_job.h"
419c8c7a7eSZhanjun Dong
429c8c7a7eSZhanjun Dong /*
438bfc4963SZhanjun Dong * struct __guc_capture_bufstate
448bfc4963SZhanjun Dong *
458bfc4963SZhanjun Dong * Book-keeping structure used to track read and write pointers
468bfc4963SZhanjun Dong * as we extract error capture data from the GuC-log-buffer's
478bfc4963SZhanjun Dong * error-capture region as a stream of dwords.
488bfc4963SZhanjun Dong */
498bfc4963SZhanjun Dong struct __guc_capture_bufstate {
508bfc4963SZhanjun Dong u32 size;
518bfc4963SZhanjun Dong u32 data_offset;
528bfc4963SZhanjun Dong u32 rd;
538bfc4963SZhanjun Dong u32 wr;
548bfc4963SZhanjun Dong };
558bfc4963SZhanjun Dong
568bfc4963SZhanjun Dong /*
578bfc4963SZhanjun Dong * struct __guc_capture_parsed_output - extracted error capture node
588bfc4963SZhanjun Dong *
598bfc4963SZhanjun Dong * A single unit of extracted error-capture output data grouped together
608bfc4963SZhanjun Dong * at an engine-instance level. We keep these nodes in a linked list.
618bfc4963SZhanjun Dong * See cachelist and outlist below.
628bfc4963SZhanjun Dong */
638bfc4963SZhanjun Dong struct __guc_capture_parsed_output {
648bfc4963SZhanjun Dong /*
658bfc4963SZhanjun Dong * A single set of 3 capture lists: a global-list
668bfc4963SZhanjun Dong * an engine-class-list and an engine-instance list.
678bfc4963SZhanjun Dong * outlist in __guc_capture_parsed_output will keep
688bfc4963SZhanjun Dong * a linked list of these nodes that will eventually
698bfc4963SZhanjun Dong * be detached from outlist and attached into to
708bfc4963SZhanjun Dong * xe_codedump in response to a context reset
718bfc4963SZhanjun Dong */
728bfc4963SZhanjun Dong struct list_head link;
738bfc4963SZhanjun Dong bool is_partial;
748bfc4963SZhanjun Dong u32 eng_class;
758bfc4963SZhanjun Dong u32 eng_inst;
768bfc4963SZhanjun Dong u32 guc_id;
778bfc4963SZhanjun Dong u32 lrca;
78ecb63364SZhanjun Dong u32 type;
79ecb63364SZhanjun Dong bool locked;
80ecb63364SZhanjun Dong enum xe_hw_engine_snapshot_source_id source;
818bfc4963SZhanjun Dong struct gcap_reg_list_info {
828bfc4963SZhanjun Dong u32 vfid;
838bfc4963SZhanjun Dong u32 num_regs;
848bfc4963SZhanjun Dong struct guc_mmio_reg *regs;
858bfc4963SZhanjun Dong } reginfo[GUC_STATE_CAPTURE_TYPE_MAX];
868bfc4963SZhanjun Dong #define GCAP_PARSED_REGLIST_INDEX_GLOBAL BIT(GUC_STATE_CAPTURE_TYPE_GLOBAL)
878bfc4963SZhanjun Dong #define GCAP_PARSED_REGLIST_INDEX_ENGCLASS BIT(GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS)
888bfc4963SZhanjun Dong };
898bfc4963SZhanjun Dong
908bfc4963SZhanjun Dong /*
919c8c7a7eSZhanjun Dong * Define all device tables of GuC error capture register lists
929c8c7a7eSZhanjun Dong * NOTE:
939c8c7a7eSZhanjun Dong * For engine-registers, GuC only needs the register offsets
949c8c7a7eSZhanjun Dong * from the engine-mmio-base
959c8c7a7eSZhanjun Dong *
969c8c7a7eSZhanjun Dong * 64 bit registers need 2 entries for low 32 bit register and high 32 bit
979c8c7a7eSZhanjun Dong * register, for example:
989c8c7a7eSZhanjun Dong * Register data_type flags mask Register name
999c8c7a7eSZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1009c8c7a7eSZhanjun Dong * { XXX_REG_HI(0), REG_64BIT_HI_DW,, 0, 0, "XXX_REG"},
1019c8c7a7eSZhanjun Dong * 1. data_type: Indicate is hi/low 32 bit for a 64 bit register
1029c8c7a7eSZhanjun Dong * A 64 bit register define requires 2 consecutive entries,
1039c8c7a7eSZhanjun Dong * with low dword first and hi dword the second.
1049c8c7a7eSZhanjun Dong * 2. Register name: null for incompleted define
105*44958161SZhanjun Dong * 3. Incorrect order will trigger XE_WARN.
1069c8c7a7eSZhanjun Dong */
1079c8c7a7eSZhanjun Dong #define COMMON_XELP_BASE_GLOBAL \
1089c8c7a7eSZhanjun Dong { FORCEWAKE_GT, REG_32BIT, 0, 0, "FORCEWAKE_GT"}
1099c8c7a7eSZhanjun Dong
1109c8c7a7eSZhanjun Dong #define COMMON_BASE_ENGINE_INSTANCE \
1119c8c7a7eSZhanjun Dong { RING_HWSTAM(0), REG_32BIT, 0, 0, "HWSTAM"}, \
1129c8c7a7eSZhanjun Dong { RING_HWS_PGA(0), REG_32BIT, 0, 0, "RING_HWS_PGA"}, \
1139c8c7a7eSZhanjun Dong { RING_HEAD(0), REG_32BIT, 0, 0, "RING_HEAD"}, \
1149c8c7a7eSZhanjun Dong { RING_TAIL(0), REG_32BIT, 0, 0, "RING_TAIL"}, \
1159c8c7a7eSZhanjun Dong { RING_CTL(0), REG_32BIT, 0, 0, "RING_CTL"}, \
1169c8c7a7eSZhanjun Dong { RING_MI_MODE(0), REG_32BIT, 0, 0, "RING_MI_MODE"}, \
1179c8c7a7eSZhanjun Dong { RING_MODE(0), REG_32BIT, 0, 0, "RING_MODE"}, \
1189c8c7a7eSZhanjun Dong { RING_ESR(0), REG_32BIT, 0, 0, "RING_ESR"}, \
1199c8c7a7eSZhanjun Dong { RING_EMR(0), REG_32BIT, 0, 0, "RING_EMR"}, \
1209c8c7a7eSZhanjun Dong { RING_EIR(0), REG_32BIT, 0, 0, "RING_EIR"}, \
1219c8c7a7eSZhanjun Dong { RING_IMR(0), REG_32BIT, 0, 0, "RING_IMR"}, \
1229c8c7a7eSZhanjun Dong { RING_IPEHR(0), REG_32BIT, 0, 0, "IPEHR"}, \
1239c8c7a7eSZhanjun Dong { RING_INSTDONE(0), REG_32BIT, 0, 0, "RING_INSTDONE"}, \
1249c8c7a7eSZhanjun Dong { INDIRECT_RING_STATE(0), REG_32BIT, 0, 0, "INDIRECT_RING_STATE"}, \
1259c8c7a7eSZhanjun Dong { RING_ACTHD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1269c8c7a7eSZhanjun Dong { RING_ACTHD_UDW(0), REG_64BIT_HI_DW, 0, 0, "ACTHD"}, \
1279c8c7a7eSZhanjun Dong { RING_BBADDR(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1289c8c7a7eSZhanjun Dong { RING_BBADDR_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_BBADDR"}, \
1299c8c7a7eSZhanjun Dong { RING_START(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1309c8c7a7eSZhanjun Dong { RING_START_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_START"}, \
1319c8c7a7eSZhanjun Dong { RING_DMA_FADD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1329c8c7a7eSZhanjun Dong { RING_DMA_FADD_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_DMA_FADD"}, \
1339c8c7a7eSZhanjun Dong { RING_EXECLIST_STATUS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1349c8c7a7eSZhanjun Dong { RING_EXECLIST_STATUS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_STATUS"}, \
1359c8c7a7eSZhanjun Dong { RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
1369c8c7a7eSZhanjun Dong { RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_SQ_CONTENTS"}
1379c8c7a7eSZhanjun Dong
1389c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS \
1399c8c7a7eSZhanjun Dong { RCU_MODE, REG_32BIT, 0, 0, "RCU_MODE"}
1409c8c7a7eSZhanjun Dong
1419c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS_INSTDONE \
1429c8c7a7eSZhanjun Dong { SC_INSTDONE, REG_32BIT, 0, 0, "SC_INSTDONE"}, \
1439c8c7a7eSZhanjun Dong { SC_INSTDONE_EXTRA, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA"}, \
1449c8c7a7eSZhanjun Dong { SC_INSTDONE_EXTRA2, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA2"}
1459c8c7a7eSZhanjun Dong
1469c8c7a7eSZhanjun Dong #define XELP_VEC_CLASS_REGS \
1479c8c7a7eSZhanjun Dong { SFC_DONE(0), 0, 0, 0, "SFC_DONE[0]"}, \
1489c8c7a7eSZhanjun Dong { SFC_DONE(1), 0, 0, 0, "SFC_DONE[1]"}, \
1499c8c7a7eSZhanjun Dong { SFC_DONE(2), 0, 0, 0, "SFC_DONE[2]"}, \
1509c8c7a7eSZhanjun Dong { SFC_DONE(3), 0, 0, 0, "SFC_DONE[3]"}
1519c8c7a7eSZhanjun Dong
1529c8c7a7eSZhanjun Dong /* XE_LP Global */
1539c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
1549c8c7a7eSZhanjun Dong COMMON_XELP_BASE_GLOBAL,
1559c8c7a7eSZhanjun Dong };
1569c8c7a7eSZhanjun Dong
1579c8c7a7eSZhanjun Dong /* Render / Compute Per-Engine-Instance */
1589c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = {
1599c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE,
1609c8c7a7eSZhanjun Dong };
1619c8c7a7eSZhanjun Dong
1629c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class */
1639c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = {
1649c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS,
1659c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS_INSTDONE,
1669c8c7a7eSZhanjun Dong };
1679c8c7a7eSZhanjun Dong
1689c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class for xehpg */
1699c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = {
1709c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS,
1719c8c7a7eSZhanjun Dong };
1729c8c7a7eSZhanjun Dong
1739c8c7a7eSZhanjun Dong /* Media Decode/Encode Per-Engine-Instance */
1749c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = {
1759c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE,
1769c8c7a7eSZhanjun Dong };
1779c8c7a7eSZhanjun Dong
1789c8c7a7eSZhanjun Dong /* Video Enhancement Engine-Class */
1799c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = {
1809c8c7a7eSZhanjun Dong XELP_VEC_CLASS_REGS,
1819c8c7a7eSZhanjun Dong };
1829c8c7a7eSZhanjun Dong
1839c8c7a7eSZhanjun Dong /* Video Enhancement Per-Engine-Instance */
1849c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = {
1859c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE,
1869c8c7a7eSZhanjun Dong };
1879c8c7a7eSZhanjun Dong
1889c8c7a7eSZhanjun Dong /* Blitter Per-Engine-Instance */
1899c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = {
1909c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE,
1919c8c7a7eSZhanjun Dong };
1929c8c7a7eSZhanjun Dong
1939c8c7a7eSZhanjun Dong /* XE_LP - GSC Per-Engine-Instance */
1949c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = {
1959c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE,
1969c8c7a7eSZhanjun Dong };
1979c8c7a7eSZhanjun Dong
1989c8c7a7eSZhanjun Dong /*
1999c8c7a7eSZhanjun Dong * Empty list to prevent warnings about unknown class/instance types
2009c8c7a7eSZhanjun Dong * as not all class/instance types have entries on all platforms.
2019c8c7a7eSZhanjun Dong */
2029c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr empty_regs_list[] = {
2039c8c7a7eSZhanjun Dong };
2049c8c7a7eSZhanjun Dong
2059c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x)
2069c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x)
2079c8c7a7eSZhanjun Dong #define MAKE_REGLIST(regslist, regsowner, regstype, class) \
2089c8c7a7eSZhanjun Dong { \
2099c8c7a7eSZhanjun Dong regslist, \
2109c8c7a7eSZhanjun Dong ARRAY_SIZE(regslist), \
2119c8c7a7eSZhanjun Dong TO_GCAP_DEF_OWNER(regsowner), \
2129c8c7a7eSZhanjun Dong TO_GCAP_DEF_TYPE(regstype), \
2139c8c7a7eSZhanjun Dong class \
2149c8c7a7eSZhanjun Dong }
2159c8c7a7eSZhanjun Dong
2169c8c7a7eSZhanjun Dong /* List of lists for legacy graphic product version < 1255 */
2179c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = {
2189c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
2199c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2209c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2219c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
2229c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
2239c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2249c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2259c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
2269c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
2279c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2289c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2299c8c7a7eSZhanjun Dong {}
2309c8c7a7eSZhanjun Dong };
2319c8c7a7eSZhanjun Dong
2329c8c7a7eSZhanjun Dong /* List of lists for graphic product version >= 1255 */
2339c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = {
2349c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0),
2359c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2369c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE),
2379c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO),
2389c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO),
2399c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2409c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE),
2419c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER),
2429c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER),
2439c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2449c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER),
2459c8c7a7eSZhanjun Dong {}
2469c8c7a7eSZhanjun Dong };
2479c8c7a7eSZhanjun Dong
2489c8c7a7eSZhanjun Dong static const char * const capture_list_type_names[] = {
2499c8c7a7eSZhanjun Dong "Global",
2509c8c7a7eSZhanjun Dong "Class",
2519c8c7a7eSZhanjun Dong "Instance",
2529c8c7a7eSZhanjun Dong };
2539c8c7a7eSZhanjun Dong
2549c8c7a7eSZhanjun Dong static const char * const capture_engine_class_names[] = {
2559c8c7a7eSZhanjun Dong "Render/Compute",
2569c8c7a7eSZhanjun Dong "Video",
2579c8c7a7eSZhanjun Dong "VideoEnhance",
2589c8c7a7eSZhanjun Dong "Blitter",
2599c8c7a7eSZhanjun Dong "GSC-Other",
2609c8c7a7eSZhanjun Dong };
2619c8c7a7eSZhanjun Dong
2629c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache {
2639c8c7a7eSZhanjun Dong bool is_valid;
2649c8c7a7eSZhanjun Dong void *ptr;
2659c8c7a7eSZhanjun Dong size_t size;
2669c8c7a7eSZhanjun Dong int status;
2679c8c7a7eSZhanjun Dong };
2689c8c7a7eSZhanjun Dong
2699c8c7a7eSZhanjun Dong struct xe_guc_state_capture {
2709c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *reglists;
271b170d696SZhanjun Dong /**
272b170d696SZhanjun Dong * NOTE: steered registers have multiple instances depending on the HW configuration
273b170d696SZhanjun Dong * (slices or dual-sub-slices) and thus depends on HW fuses discovered
274b170d696SZhanjun Dong */
275b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists;
2769c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX]
2779c8c7a7eSZhanjun Dong [GUC_STATE_CAPTURE_TYPE_MAX]
2789c8c7a7eSZhanjun Dong [GUC_CAPTURE_LIST_CLASS_MAX];
2799c8c7a7eSZhanjun Dong void *ads_null_cache;
2808bfc4963SZhanjun Dong struct list_head cachelist;
2818bfc4963SZhanjun Dong #define PREALLOC_NODES_MAX_COUNT (3 * GUC_MAX_ENGINE_CLASSES * GUC_MAX_INSTANCES_PER_CLASS)
2828bfc4963SZhanjun Dong #define PREALLOC_NODES_DEFAULT_NUMREGS 64
2838bfc4963SZhanjun Dong
2848bfc4963SZhanjun Dong int max_mmio_per_node;
2858bfc4963SZhanjun Dong struct list_head outlist;
2869c8c7a7eSZhanjun Dong };
2879c8c7a7eSZhanjun Dong
288ecb63364SZhanjun Dong static void
289ecb63364SZhanjun Dong guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture *gc,
290ecb63364SZhanjun Dong struct __guc_capture_parsed_output *node);
291ecb63364SZhanjun Dong
2929c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group *
guc_capture_get_device_reglist(struct xe_device * xe)2939c8c7a7eSZhanjun Dong guc_capture_get_device_reglist(struct xe_device *xe)
2949c8c7a7eSZhanjun Dong {
2959c8c7a7eSZhanjun Dong if (GRAPHICS_VERx100(xe) >= 1255)
2969c8c7a7eSZhanjun Dong return xe_hpg_lists;
2979c8c7a7eSZhanjun Dong else
2989c8c7a7eSZhanjun Dong return xe_lp_lists;
2999c8c7a7eSZhanjun Dong }
3009c8c7a7eSZhanjun Dong
3019c8c7a7eSZhanjun Dong 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)3029c8c7a7eSZhanjun Dong guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
3039c8c7a7eSZhanjun Dong u32 owner, u32 type, enum guc_capture_list_class_type capture_class)
3049c8c7a7eSZhanjun Dong {
3059c8c7a7eSZhanjun Dong int i;
3069c8c7a7eSZhanjun Dong
3079c8c7a7eSZhanjun Dong if (!reglists)
3089c8c7a7eSZhanjun Dong return NULL;
3099c8c7a7eSZhanjun Dong
3109c8c7a7eSZhanjun Dong for (i = 0; reglists[i].list; ++i) {
3119c8c7a7eSZhanjun Dong if (reglists[i].owner == owner && reglists[i].type == type &&
3129c8c7a7eSZhanjun Dong (reglists[i].engine == capture_class ||
3139c8c7a7eSZhanjun Dong reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL))
3149c8c7a7eSZhanjun Dong return ®lists[i];
3159c8c7a7eSZhanjun Dong }
3169c8c7a7eSZhanjun Dong
3179c8c7a7eSZhanjun Dong return NULL;
3189c8c7a7eSZhanjun Dong }
3199c8c7a7eSZhanjun Dong
320ecb63364SZhanjun Dong 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)321ecb63364SZhanjun Dong xe_guc_capture_get_reg_desc_list(struct xe_gt *gt, u32 owner, u32 type,
322ecb63364SZhanjun Dong enum guc_capture_list_class_type capture_class, bool is_ext)
323ecb63364SZhanjun Dong {
324ecb63364SZhanjun Dong const struct __guc_mmio_reg_descr_group *reglists;
325ecb63364SZhanjun Dong
326ecb63364SZhanjun Dong if (is_ext) {
327ecb63364SZhanjun Dong struct xe_guc *guc = >->uc.guc;
328ecb63364SZhanjun Dong
329ecb63364SZhanjun Dong reglists = guc->capture->extlists;
330ecb63364SZhanjun Dong } else {
331ecb63364SZhanjun Dong reglists = guc_capture_get_device_reglist(gt_to_xe(gt));
332ecb63364SZhanjun Dong }
333ecb63364SZhanjun Dong return guc_capture_get_one_list(reglists, owner, type, capture_class);
334ecb63364SZhanjun Dong }
335ecb63364SZhanjun Dong
336b170d696SZhanjun Dong struct __ext_steer_reg {
337b170d696SZhanjun Dong const char *name;
338b170d696SZhanjun Dong struct xe_reg_mcr reg;
339b170d696SZhanjun Dong };
340b170d696SZhanjun Dong
341b170d696SZhanjun Dong static const struct __ext_steer_reg xe_extregs[] = {
342b170d696SZhanjun Dong {"SAMPLER_INSTDONE", SAMPLER_INSTDONE},
343b170d696SZhanjun Dong {"ROW_INSTDONE", ROW_INSTDONE}
344b170d696SZhanjun Dong };
345b170d696SZhanjun Dong
346b170d696SZhanjun Dong static const struct __ext_steer_reg xehpg_extregs[] = {
347b170d696SZhanjun Dong {"SC_INSTDONE", XEHPG_SC_INSTDONE},
348b170d696SZhanjun Dong {"SC_INSTDONE_EXTRA", XEHPG_SC_INSTDONE_EXTRA},
349b170d696SZhanjun Dong {"SC_INSTDONE_EXTRA2", XEHPG_SC_INSTDONE_EXTRA2},
350b170d696SZhanjun Dong {"INSTDONE_GEOM_SVGUNIT", XEHPG_INSTDONE_GEOM_SVGUNIT}
351b170d696SZhanjun Dong };
352b170d696SZhanjun Dong
__fill_ext_reg(struct __guc_mmio_reg_descr * ext,const struct __ext_steer_reg * extlist,int slice_id,int subslice_id)353b170d696SZhanjun Dong static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
354b170d696SZhanjun Dong const struct __ext_steer_reg *extlist,
355b170d696SZhanjun Dong int slice_id, int subslice_id)
356b170d696SZhanjun Dong {
357b170d696SZhanjun Dong if (!ext || !extlist)
358b170d696SZhanjun Dong return;
359b170d696SZhanjun Dong
360b170d696SZhanjun Dong ext->reg = XE_REG(extlist->reg.__reg.addr);
361b170d696SZhanjun Dong ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1);
362b170d696SZhanjun Dong ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
363b170d696SZhanjun Dong ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
364b170d696SZhanjun Dong ext->regname = extlist->name;
365b170d696SZhanjun Dong }
366b170d696SZhanjun Dong
367b170d696SZhanjun Dong 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)368b170d696SZhanjun Dong __alloc_ext_regs(struct drm_device *drm, struct __guc_mmio_reg_descr_group *newlist,
369b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *rootlist, int num_regs)
370b170d696SZhanjun Dong {
371b170d696SZhanjun Dong struct __guc_mmio_reg_descr *list;
372b170d696SZhanjun Dong
373b170d696SZhanjun Dong list = drmm_kzalloc(drm, num_regs * sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL);
374b170d696SZhanjun Dong if (!list)
375b170d696SZhanjun Dong return -ENOMEM;
376b170d696SZhanjun Dong
377b170d696SZhanjun Dong newlist->list = list;
378b170d696SZhanjun Dong newlist->num_regs = num_regs;
379b170d696SZhanjun Dong newlist->owner = rootlist->owner;
380b170d696SZhanjun Dong newlist->engine = rootlist->engine;
381b170d696SZhanjun Dong newlist->type = rootlist->type;
382b170d696SZhanjun Dong
383b170d696SZhanjun Dong return 0;
384b170d696SZhanjun Dong }
385b170d696SZhanjun Dong
guc_capture_get_steer_reg_num(struct xe_device * xe)386b170d696SZhanjun Dong static int guc_capture_get_steer_reg_num(struct xe_device *xe)
387b170d696SZhanjun Dong {
388b170d696SZhanjun Dong int num = ARRAY_SIZE(xe_extregs);
389b170d696SZhanjun Dong
390b170d696SZhanjun Dong if (GRAPHICS_VERx100(xe) >= 1255)
391b170d696SZhanjun Dong num += ARRAY_SIZE(xehpg_extregs);
392b170d696SZhanjun Dong
393b170d696SZhanjun Dong return num;
394b170d696SZhanjun Dong }
395b170d696SZhanjun Dong
guc_capture_alloc_steered_lists(struct xe_guc * guc)396b170d696SZhanjun Dong static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
397b170d696SZhanjun Dong {
398b170d696SZhanjun Dong struct xe_gt *gt = guc_to_gt(guc);
399b170d696SZhanjun Dong u16 slice, subslice;
400b170d696SZhanjun Dong int iter, i, total = 0;
401b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists;
402b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *list;
403b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists;
404b170d696SZhanjun Dong struct __guc_mmio_reg_descr *extarray;
405b170d696SZhanjun Dong bool has_xehpg_extregs = GRAPHICS_VERx100(gt_to_xe(gt)) >= 1255;
406b170d696SZhanjun Dong struct drm_device *drm = >_to_xe(gt)->drm;
407b170d696SZhanjun Dong bool has_rcs_ccs = false;
408b170d696SZhanjun Dong struct xe_hw_engine *hwe;
409b170d696SZhanjun Dong enum xe_hw_engine_id id;
410b170d696SZhanjun Dong
411b170d696SZhanjun Dong /*
412b170d696SZhanjun Dong * If GT has no rcs/ccs, no need to alloc steered list.
413b170d696SZhanjun Dong * Currently, only rcs/ccs has steering register, if in the future,
414b170d696SZhanjun Dong * other engine types has steering register, this condition check need
415b170d696SZhanjun Dong * to be extended
416b170d696SZhanjun Dong */
417b170d696SZhanjun Dong for_each_hw_engine(hwe, gt, id) {
418b170d696SZhanjun Dong if (xe_engine_class_to_guc_capture_class(hwe->class) ==
419b170d696SZhanjun Dong GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
420b170d696SZhanjun Dong has_rcs_ccs = true;
421b170d696SZhanjun Dong break;
422b170d696SZhanjun Dong }
423b170d696SZhanjun Dong }
424b170d696SZhanjun Dong
425b170d696SZhanjun Dong if (!has_rcs_ccs)
426b170d696SZhanjun Dong return;
427b170d696SZhanjun Dong
428b170d696SZhanjun Dong /* steered registers currently only exist for the render-class */
429b170d696SZhanjun Dong list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF,
430b170d696SZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
431b170d696SZhanjun Dong GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE);
432b170d696SZhanjun Dong /*
433b170d696SZhanjun Dong * Skip if this platform has no engine class registers or if extlists
434b170d696SZhanjun Dong * was previously allocated
435b170d696SZhanjun Dong */
436b170d696SZhanjun Dong if (!list || guc->capture->extlists)
437b170d696SZhanjun Dong return;
438b170d696SZhanjun Dong
439b170d696SZhanjun Dong total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) *
440b170d696SZhanjun Dong guc_capture_get_steer_reg_num(guc_to_xe(guc));
441b170d696SZhanjun Dong
442b170d696SZhanjun Dong if (!total)
443b170d696SZhanjun Dong return;
444b170d696SZhanjun Dong
445b170d696SZhanjun Dong /* allocate an extra for an end marker */
446b170d696SZhanjun Dong extlists = drmm_kzalloc(drm, 2 * sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL);
447b170d696SZhanjun Dong if (!extlists)
448b170d696SZhanjun Dong return;
449b170d696SZhanjun Dong
450b170d696SZhanjun Dong if (__alloc_ext_regs(drm, &extlists[0], list, total)) {
451b170d696SZhanjun Dong drmm_kfree(drm, extlists);
452b170d696SZhanjun Dong return;
453b170d696SZhanjun Dong }
454b170d696SZhanjun Dong
455b170d696SZhanjun Dong /* For steering registers, the list is generated at run-time */
456b170d696SZhanjun Dong extarray = (struct __guc_mmio_reg_descr *)extlists[0].list;
457b170d696SZhanjun Dong for_each_dss_steering(iter, gt, slice, subslice) {
458b170d696SZhanjun Dong for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) {
459b170d696SZhanjun Dong __fill_ext_reg(extarray, &xe_extregs[i], slice, subslice);
460b170d696SZhanjun Dong ++extarray;
461b170d696SZhanjun Dong }
462b170d696SZhanjun Dong
463b170d696SZhanjun Dong if (has_xehpg_extregs)
464b170d696SZhanjun Dong for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {
465b170d696SZhanjun Dong __fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice);
466b170d696SZhanjun Dong ++extarray;
467b170d696SZhanjun Dong }
468b170d696SZhanjun Dong }
469b170d696SZhanjun Dong
470b170d696SZhanjun Dong extlists[0].num_regs = total;
471b170d696SZhanjun Dong
472b170d696SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "capture found %d ext-regs.\n", total);
473b170d696SZhanjun Dong guc->capture->extlists = extlists;
474b170d696SZhanjun Dong }
475b170d696SZhanjun Dong
4769c8c7a7eSZhanjun Dong 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)4779c8c7a7eSZhanjun Dong guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
4789c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr,
4799c8c7a7eSZhanjun Dong u16 num_entries)
4809c8c7a7eSZhanjun Dong {
481b170d696SZhanjun Dong u32 ptr_idx = 0, list_idx = 0;
4829c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists;
483b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists;
4849c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *match;
485b170d696SZhanjun Dong u32 list_num;
4869c8c7a7eSZhanjun Dong
4879c8c7a7eSZhanjun Dong if (!reglists)
4889c8c7a7eSZhanjun Dong return -ENODEV;
4899c8c7a7eSZhanjun Dong
4909c8c7a7eSZhanjun Dong match = guc_capture_get_one_list(reglists, owner, type, capture_class);
4919c8c7a7eSZhanjun Dong if (!match)
4929c8c7a7eSZhanjun Dong return -ENODATA;
4939c8c7a7eSZhanjun Dong
494b170d696SZhanjun Dong list_num = match->num_regs;
495b170d696SZhanjun Dong for (list_idx = 0; ptr_idx < num_entries && list_idx < list_num; ++list_idx, ++ptr_idx) {
496b170d696SZhanjun Dong ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
497b170d696SZhanjun Dong ptr[ptr_idx].value = 0xDEADF00D;
498b170d696SZhanjun Dong ptr[ptr_idx].flags = match->list[list_idx].flags;
499b170d696SZhanjun Dong ptr[ptr_idx].mask = match->list[list_idx].mask;
5009c8c7a7eSZhanjun Dong }
5019c8c7a7eSZhanjun Dong
502b170d696SZhanjun Dong match = guc_capture_get_one_list(extlists, owner, type, capture_class);
503b170d696SZhanjun Dong if (match)
504b170d696SZhanjun Dong for (ptr_idx = list_num, list_idx = 0;
505b170d696SZhanjun Dong ptr_idx < num_entries && list_idx < match->num_regs;
506b170d696SZhanjun Dong ++ptr_idx, ++list_idx) {
507b170d696SZhanjun Dong ptr[ptr_idx].offset = match->list[list_idx].reg.addr;
508b170d696SZhanjun Dong ptr[ptr_idx].value = 0xDEADF00D;
509b170d696SZhanjun Dong ptr[ptr_idx].flags = match->list[list_idx].flags;
510b170d696SZhanjun Dong ptr[ptr_idx].mask = match->list[list_idx].mask;
511b170d696SZhanjun Dong }
512b170d696SZhanjun Dong
513b170d696SZhanjun Dong if (ptr_idx < num_entries)
514b170d696SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out-of %d.\n",
515b170d696SZhanjun Dong ptr_idx, num_entries);
5169c8c7a7eSZhanjun Dong
5179c8c7a7eSZhanjun Dong return 0;
5189c8c7a7eSZhanjun Dong }
5199c8c7a7eSZhanjun Dong
5209c8c7a7eSZhanjun Dong static int
guc_cap_list_num_regs(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class)5219c8c7a7eSZhanjun Dong guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
5229c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class)
5239c8c7a7eSZhanjun Dong {
5249c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *match;
525b170d696SZhanjun Dong int num_regs = 0;
5269c8c7a7eSZhanjun Dong
5279c8c7a7eSZhanjun Dong match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class);
528b170d696SZhanjun Dong if (match)
529b170d696SZhanjun Dong num_regs = match->num_regs;
5309c8c7a7eSZhanjun Dong
531b170d696SZhanjun Dong match = guc_capture_get_one_list(guc->capture->extlists, owner, type, capture_class);
532b170d696SZhanjun Dong if (match)
533b170d696SZhanjun Dong num_regs += match->num_regs;
534b170d696SZhanjun Dong else
5358bfc4963SZhanjun Dong /*
5368bfc4963SZhanjun Dong * If a caller wants the full register dump size but we have
5378bfc4963SZhanjun Dong * not yet got the hw-config, which is before max_mmio_per_node
5388bfc4963SZhanjun Dong * is initialized, then provide a worst-case number for
5398bfc4963SZhanjun Dong * extlists based on max dss fuse bits, but only ever for
5408bfc4963SZhanjun Dong * render/compute
5418bfc4963SZhanjun Dong */
5428bfc4963SZhanjun Dong if (owner == GUC_CAPTURE_LIST_INDEX_PF &&
5438bfc4963SZhanjun Dong type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
5448bfc4963SZhanjun Dong capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE &&
5458bfc4963SZhanjun Dong !guc->capture->max_mmio_per_node)
546b170d696SZhanjun Dong num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) *
547b170d696SZhanjun Dong XE_MAX_DSS_FUSE_BITS;
548b170d696SZhanjun Dong
549b170d696SZhanjun Dong return num_regs;
5509c8c7a7eSZhanjun Dong }
5519c8c7a7eSZhanjun Dong
5529c8c7a7eSZhanjun Dong 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)5539c8c7a7eSZhanjun Dong guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
5549c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class,
5559c8c7a7eSZhanjun Dong size_t *size, bool is_purpose_est)
5569c8c7a7eSZhanjun Dong {
5579c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture;
5589c8c7a7eSZhanjun Dong struct xe_gt *gt = guc_to_gt(guc);
5599c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache *cache;
5609c8c7a7eSZhanjun Dong int num_regs;
5619c8c7a7eSZhanjun Dong
5629c8c7a7eSZhanjun Dong xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX);
5639c8c7a7eSZhanjun Dong xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX);
5649c8c7a7eSZhanjun Dong
5659c8c7a7eSZhanjun Dong cache = &gc->ads_cache[owner][type][capture_class];
5669c8c7a7eSZhanjun Dong if (!gc->reglists) {
5679c8c7a7eSZhanjun Dong xe_gt_warn(gt, "No capture reglist for this device\n");
5689c8c7a7eSZhanjun Dong return -ENODEV;
5699c8c7a7eSZhanjun Dong }
5709c8c7a7eSZhanjun Dong
5719c8c7a7eSZhanjun Dong if (cache->is_valid) {
5729c8c7a7eSZhanjun Dong *size = cache->size;
5739c8c7a7eSZhanjun Dong return cache->status;
5749c8c7a7eSZhanjun Dong }
5759c8c7a7eSZhanjun Dong
5769c8c7a7eSZhanjun Dong if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF &&
5779c8c7a7eSZhanjun Dong !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) {
5789c8c7a7eSZhanjun Dong if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL)
5799c8c7a7eSZhanjun Dong xe_gt_warn(gt, "Missing capture reglist: global!\n");
5809c8c7a7eSZhanjun Dong else
5819c8c7a7eSZhanjun Dong xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n",
5829c8c7a7eSZhanjun Dong capture_list_type_names[type], type,
5839c8c7a7eSZhanjun Dong capture_engine_class_names[capture_class], capture_class);
5849c8c7a7eSZhanjun Dong return -ENODEV;
5859c8c7a7eSZhanjun Dong }
5869c8c7a7eSZhanjun Dong
5879c8c7a7eSZhanjun Dong num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
5889c8c7a7eSZhanjun Dong /* intentional empty lists can exist depending on hw config */
5899c8c7a7eSZhanjun Dong if (!num_regs)
5909c8c7a7eSZhanjun Dong return -ENODATA;
5919c8c7a7eSZhanjun Dong
5929c8c7a7eSZhanjun Dong if (size)
5939c8c7a7eSZhanjun Dong *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) +
5949c8c7a7eSZhanjun Dong (num_regs * sizeof(struct guc_mmio_reg)));
5959c8c7a7eSZhanjun Dong
5969c8c7a7eSZhanjun Dong return 0;
5979c8c7a7eSZhanjun Dong }
5989c8c7a7eSZhanjun Dong
5999c8c7a7eSZhanjun Dong /**
6009c8c7a7eSZhanjun Dong * xe_guc_capture_getlistsize - Get list size for owner/type/class combination
6019c8c7a7eSZhanjun Dong * @guc: The GuC object
6029c8c7a7eSZhanjun Dong * @owner: PF/VF owner
6039c8c7a7eSZhanjun Dong * @type: GuC capture register type
6049c8c7a7eSZhanjun Dong * @capture_class: GuC capture engine class id
6059c8c7a7eSZhanjun Dong * @size: Point to the size
6069c8c7a7eSZhanjun Dong *
6079c8c7a7eSZhanjun Dong * This function will get the list for the owner/type/class combination, and
6089c8c7a7eSZhanjun Dong * return the page aligned list size.
6099c8c7a7eSZhanjun Dong *
6109c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure.
6119c8c7a7eSZhanjun Dong */
6129c8c7a7eSZhanjun Dong int
xe_guc_capture_getlistsize(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,size_t * size)6139c8c7a7eSZhanjun Dong xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type,
6149c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, size_t *size)
6159c8c7a7eSZhanjun Dong {
6169c8c7a7eSZhanjun Dong return guc_capture_getlistsize(guc, owner, type, capture_class, size, false);
6179c8c7a7eSZhanjun Dong }
6189c8c7a7eSZhanjun Dong
6199c8c7a7eSZhanjun Dong /**
6209c8c7a7eSZhanjun Dong * xe_guc_capture_getlist - Get register capture list for owner/type/class
6219c8c7a7eSZhanjun Dong * combination
6229c8c7a7eSZhanjun Dong * @guc: The GuC object
6239c8c7a7eSZhanjun Dong * @owner: PF/VF owner
6249c8c7a7eSZhanjun Dong * @type: GuC capture register type
6259c8c7a7eSZhanjun Dong * @capture_class: GuC capture engine class id
6269c8c7a7eSZhanjun Dong * @outptr: Point to cached register capture list
6279c8c7a7eSZhanjun Dong *
6289c8c7a7eSZhanjun Dong * This function will get the register capture list for the owner/type/class
6299c8c7a7eSZhanjun Dong * combination.
6309c8c7a7eSZhanjun Dong *
6319c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure.
6329c8c7a7eSZhanjun Dong */
6339c8c7a7eSZhanjun Dong int
xe_guc_capture_getlist(struct xe_guc * guc,u32 owner,u32 type,enum guc_capture_list_class_type capture_class,void ** outptr)6349c8c7a7eSZhanjun Dong xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type,
6359c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, void **outptr)
6369c8c7a7eSZhanjun Dong {
6379c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture;
6389c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class];
6399c8c7a7eSZhanjun Dong struct guc_debug_capture_list *listnode;
6409c8c7a7eSZhanjun Dong int ret, num_regs;
6419c8c7a7eSZhanjun Dong u8 *caplist, *tmp;
6429c8c7a7eSZhanjun Dong size_t size = 0;
6439c8c7a7eSZhanjun Dong
6449c8c7a7eSZhanjun Dong if (!gc->reglists)
6459c8c7a7eSZhanjun Dong return -ENODEV;
6469c8c7a7eSZhanjun Dong
6479c8c7a7eSZhanjun Dong if (cache->is_valid) {
6489c8c7a7eSZhanjun Dong *outptr = cache->ptr;
6499c8c7a7eSZhanjun Dong return cache->status;
6509c8c7a7eSZhanjun Dong }
6519c8c7a7eSZhanjun Dong
6529c8c7a7eSZhanjun Dong ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size);
6539c8c7a7eSZhanjun Dong if (ret) {
6549c8c7a7eSZhanjun Dong cache->is_valid = true;
6559c8c7a7eSZhanjun Dong cache->ptr = NULL;
6569c8c7a7eSZhanjun Dong cache->size = 0;
6579c8c7a7eSZhanjun Dong cache->status = ret;
6589c8c7a7eSZhanjun Dong return ret;
6599c8c7a7eSZhanjun Dong }
6609c8c7a7eSZhanjun Dong
6619c8c7a7eSZhanjun Dong caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL);
6629c8c7a7eSZhanjun Dong if (!caplist)
6639c8c7a7eSZhanjun Dong return -ENOMEM;
6649c8c7a7eSZhanjun Dong
6659c8c7a7eSZhanjun Dong /* populate capture list header */
6669c8c7a7eSZhanjun Dong tmp = caplist;
6679c8c7a7eSZhanjun Dong num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class);
6689c8c7a7eSZhanjun Dong listnode = (struct guc_debug_capture_list *)tmp;
6699c8c7a7eSZhanjun Dong listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs);
6709c8c7a7eSZhanjun Dong
6719c8c7a7eSZhanjun Dong /* populate list of register descriptor */
6729c8c7a7eSZhanjun Dong tmp += sizeof(struct guc_debug_capture_list);
6739c8c7a7eSZhanjun Dong guc_capture_list_init(guc, owner, type, capture_class,
6749c8c7a7eSZhanjun Dong (struct guc_mmio_reg *)tmp, num_regs);
6759c8c7a7eSZhanjun Dong
6769c8c7a7eSZhanjun Dong /* cache this list */
6779c8c7a7eSZhanjun Dong cache->is_valid = true;
6789c8c7a7eSZhanjun Dong cache->ptr = caplist;
6799c8c7a7eSZhanjun Dong cache->size = size;
6809c8c7a7eSZhanjun Dong cache->status = 0;
6819c8c7a7eSZhanjun Dong
6829c8c7a7eSZhanjun Dong *outptr = caplist;
6839c8c7a7eSZhanjun Dong
6849c8c7a7eSZhanjun Dong return 0;
6859c8c7a7eSZhanjun Dong }
6869c8c7a7eSZhanjun Dong
6879c8c7a7eSZhanjun Dong /**
6889c8c7a7eSZhanjun Dong * xe_guc_capture_getnullheader - Get a null list for register capture
6899c8c7a7eSZhanjun Dong * @guc: The GuC object
6909c8c7a7eSZhanjun Dong * @outptr: Point to cached register capture list
6919c8c7a7eSZhanjun Dong * @size: Point to the size
6929c8c7a7eSZhanjun Dong *
6939c8c7a7eSZhanjun Dong * This function will alloc for a null list for register capture.
6949c8c7a7eSZhanjun Dong *
6959c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure.
6969c8c7a7eSZhanjun Dong */
6979c8c7a7eSZhanjun Dong int
xe_guc_capture_getnullheader(struct xe_guc * guc,void ** outptr,size_t * size)6989c8c7a7eSZhanjun Dong xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size)
6999c8c7a7eSZhanjun Dong {
7009c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture;
7019c8c7a7eSZhanjun Dong int tmp = sizeof(u32) * 4;
7029c8c7a7eSZhanjun Dong void *null_header;
7039c8c7a7eSZhanjun Dong
7049c8c7a7eSZhanjun Dong if (gc->ads_null_cache) {
7059c8c7a7eSZhanjun Dong *outptr = gc->ads_null_cache;
7069c8c7a7eSZhanjun Dong *size = tmp;
7079c8c7a7eSZhanjun Dong return 0;
7089c8c7a7eSZhanjun Dong }
7099c8c7a7eSZhanjun Dong
7109c8c7a7eSZhanjun Dong null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL);
7119c8c7a7eSZhanjun Dong if (!null_header)
7129c8c7a7eSZhanjun Dong return -ENOMEM;
7139c8c7a7eSZhanjun Dong
7149c8c7a7eSZhanjun Dong gc->ads_null_cache = null_header;
7159c8c7a7eSZhanjun Dong *outptr = null_header;
7169c8c7a7eSZhanjun Dong *size = tmp;
7179c8c7a7eSZhanjun Dong
7189c8c7a7eSZhanjun Dong return 0;
7199c8c7a7eSZhanjun Dong }
7209c8c7a7eSZhanjun Dong
7219c8c7a7eSZhanjun Dong /**
7229c8c7a7eSZhanjun Dong * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture
7239c8c7a7eSZhanjun Dong * @guc: point to xe_guc structure
7249c8c7a7eSZhanjun Dong *
7259c8c7a7eSZhanjun Dong * Calculate the worst size for GuC register capture by including all possible engines classes.
7269c8c7a7eSZhanjun Dong *
7279c8c7a7eSZhanjun Dong * Returns: Calculated size
7289c8c7a7eSZhanjun Dong */
xe_guc_capture_ads_input_worst_size(struct xe_guc * guc)7299c8c7a7eSZhanjun Dong size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
7309c8c7a7eSZhanjun Dong {
7319c8c7a7eSZhanjun Dong size_t total_size, class_size, instance_size, global_size;
7329c8c7a7eSZhanjun Dong int i, j;
7339c8c7a7eSZhanjun Dong
7349c8c7a7eSZhanjun Dong /*
7359c8c7a7eSZhanjun Dong * This function calculates the worst case register lists size by
7369c8c7a7eSZhanjun Dong * including all possible engines classes. It is called during the
7379c8c7a7eSZhanjun Dong * first of a two-phase GuC (and ADS-population) initialization
7389c8c7a7eSZhanjun Dong * sequence, that is, during the pre-hwconfig phase before we have
7399c8c7a7eSZhanjun Dong * the exact engine fusing info.
7409c8c7a7eSZhanjun Dong */
7419c8c7a7eSZhanjun Dong total_size = PAGE_SIZE; /* Pad a page in front for empty lists */
7429c8c7a7eSZhanjun Dong for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
7439c8c7a7eSZhanjun Dong for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) {
7449c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i,
7459c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
7469c8c7a7eSZhanjun Dong j, &class_size) < 0)
7479c8c7a7eSZhanjun Dong class_size = 0;
7489c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i,
7499c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
7509c8c7a7eSZhanjun Dong j, &instance_size) < 0)
7519c8c7a7eSZhanjun Dong instance_size = 0;
7529c8c7a7eSZhanjun Dong total_size += class_size + instance_size;
7539c8c7a7eSZhanjun Dong }
7549c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i,
7559c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_GLOBAL,
7569c8c7a7eSZhanjun Dong 0, &global_size) < 0)
7579c8c7a7eSZhanjun Dong global_size = 0;
7589c8c7a7eSZhanjun Dong total_size += global_size;
7599c8c7a7eSZhanjun Dong }
7609c8c7a7eSZhanjun Dong
7619c8c7a7eSZhanjun Dong return PAGE_ALIGN(total_size);
7629c8c7a7eSZhanjun Dong }
7639c8c7a7eSZhanjun Dong
guc_capture_output_size_est(struct xe_guc * guc)76484d15f42SZhanjun Dong static int guc_capture_output_size_est(struct xe_guc *guc)
76584d15f42SZhanjun Dong {
76684d15f42SZhanjun Dong struct xe_gt *gt = guc_to_gt(guc);
76784d15f42SZhanjun Dong struct xe_hw_engine *hwe;
76884d15f42SZhanjun Dong enum xe_hw_engine_id id;
76984d15f42SZhanjun Dong
77084d15f42SZhanjun Dong int capture_size = 0;
77184d15f42SZhanjun Dong size_t tmp = 0;
77284d15f42SZhanjun Dong
77384d15f42SZhanjun Dong if (!guc->capture)
77484d15f42SZhanjun Dong return -ENODEV;
77584d15f42SZhanjun Dong
77684d15f42SZhanjun Dong /*
77784d15f42SZhanjun Dong * If every single engine-instance suffered a failure in quick succession but
77884d15f42SZhanjun Dong * were all unrelated, then a burst of multiple error-capture events would dump
77984d15f42SZhanjun Dong * registers for every one engine instance, one at a time. In this case, GuC
78084d15f42SZhanjun Dong * would even dump the global-registers repeatedly.
78184d15f42SZhanjun Dong *
78284d15f42SZhanjun Dong * For each engine instance, there would be 1 x guc_state_capture_group_t output
78384d15f42SZhanjun Dong * followed by 3 x guc_state_capture_t lists. The latter is how the register
78484d15f42SZhanjun Dong * dumps are split across different register types (where the '3' are global vs class
78584d15f42SZhanjun Dong * vs instance).
78684d15f42SZhanjun Dong */
78784d15f42SZhanjun Dong for_each_hw_engine(hwe, gt, id) {
78884d15f42SZhanjun Dong enum guc_capture_list_class_type capture_class;
78984d15f42SZhanjun Dong
79084d15f42SZhanjun Dong capture_class = xe_engine_class_to_guc_capture_class(hwe->class);
79184d15f42SZhanjun Dong capture_size += sizeof(struct guc_state_capture_group_header_t) +
79284d15f42SZhanjun Dong (3 * sizeof(struct guc_state_capture_header_t));
79384d15f42SZhanjun Dong
79484d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_GLOBAL,
79584d15f42SZhanjun Dong 0, &tmp, true))
79684d15f42SZhanjun Dong capture_size += tmp;
79784d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
79884d15f42SZhanjun Dong capture_class, &tmp, true))
79984d15f42SZhanjun Dong capture_size += tmp;
80084d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE,
80184d15f42SZhanjun Dong capture_class, &tmp, true))
80284d15f42SZhanjun Dong capture_size += tmp;
80384d15f42SZhanjun Dong }
80484d15f42SZhanjun Dong
80584d15f42SZhanjun Dong return capture_size;
80684d15f42SZhanjun Dong }
80784d15f42SZhanjun Dong
80884d15f42SZhanjun Dong /*
80984d15f42SZhanjun Dong * Add on a 3x multiplier to allow for multiple back-to-back captures occurring
81084d15f42SZhanjun Dong * before the Xe can read the data out and process it
81184d15f42SZhanjun Dong */
81284d15f42SZhanjun Dong #define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3
81384d15f42SZhanjun Dong
check_guc_capture_size(struct xe_guc * guc)81484d15f42SZhanjun Dong static void check_guc_capture_size(struct xe_guc *guc)
81584d15f42SZhanjun Dong {
81684d15f42SZhanjun Dong int capture_size = guc_capture_output_size_est(guc);
81784d15f42SZhanjun Dong int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER;
81884d15f42SZhanjun Dong u32 buffer_size = xe_guc_log_section_size_capture(&guc->log);
81984d15f42SZhanjun Dong
82084d15f42SZhanjun Dong /*
82184d15f42SZhanjun Dong * NOTE: capture_size is much smaller than the capture region
82284d15f42SZhanjun Dong * allocation (DG2: <80K vs 1MB).
82384d15f42SZhanjun Dong * Additionally, its based on space needed to fit all engines getting
82484d15f42SZhanjun Dong * reset at once within the same G2H handler task slot. This is very
82584d15f42SZhanjun Dong * unlikely. However, if GuC really does run out of space for whatever
82684d15f42SZhanjun Dong * reason, we will see an separate warning message when processing the
82784d15f42SZhanjun Dong * G2H event capture-notification, search for:
82884d15f42SZhanjun Dong * xe_guc_STATE_CAPTURE_EVENT_STATUS_NOSPACE.
82984d15f42SZhanjun Dong */
83084d15f42SZhanjun Dong if (capture_size < 0)
83184d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc),
83284d15f42SZhanjun Dong "Failed to calculate error state capture buffer minimum size: %d!\n",
83384d15f42SZhanjun Dong capture_size);
83484d15f42SZhanjun Dong if (capture_size > buffer_size)
83584d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "Error state capture buffer maybe small: %d < %d\n",
83684d15f42SZhanjun Dong buffer_size, capture_size);
83784d15f42SZhanjun Dong else if (spare_size > buffer_size)
83884d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc),
83984d15f42SZhanjun Dong "Error state capture buffer lacks spare size: %d < %d (min = %d)\n",
84084d15f42SZhanjun Dong buffer_size, spare_size, capture_size);
84184d15f42SZhanjun Dong }
84284d15f42SZhanjun Dong
8438bfc4963SZhanjun Dong static void
guc_capture_add_node_to_list(struct __guc_capture_parsed_output * node,struct list_head * list)8448bfc4963SZhanjun Dong guc_capture_add_node_to_list(struct __guc_capture_parsed_output *node,
8458bfc4963SZhanjun Dong struct list_head *list)
8468bfc4963SZhanjun Dong {
847ecb63364SZhanjun Dong list_add(&node->link, list);
8488bfc4963SZhanjun Dong }
8498bfc4963SZhanjun Dong
8508bfc4963SZhanjun Dong static void
guc_capture_add_node_to_outlist(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)8518bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(struct xe_guc_state_capture *gc,
8528bfc4963SZhanjun Dong struct __guc_capture_parsed_output *node)
8538bfc4963SZhanjun Dong {
854ecb63364SZhanjun Dong guc_capture_remove_stale_matches_from_list(gc, node);
8558bfc4963SZhanjun Dong guc_capture_add_node_to_list(node, &gc->outlist);
8568bfc4963SZhanjun Dong }
8578bfc4963SZhanjun Dong
8588bfc4963SZhanjun Dong static void
guc_capture_add_node_to_cachelist(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)8598bfc4963SZhanjun Dong guc_capture_add_node_to_cachelist(struct xe_guc_state_capture *gc,
8608bfc4963SZhanjun Dong struct __guc_capture_parsed_output *node)
8618bfc4963SZhanjun Dong {
8628bfc4963SZhanjun Dong guc_capture_add_node_to_list(node, &gc->cachelist);
8638bfc4963SZhanjun Dong }
8648bfc4963SZhanjun Dong
8658bfc4963SZhanjun Dong static void
guc_capture_free_outlist_node(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * n)866ecb63364SZhanjun Dong guc_capture_free_outlist_node(struct xe_guc_state_capture *gc,
867ecb63364SZhanjun Dong struct __guc_capture_parsed_output *n)
868ecb63364SZhanjun Dong {
869ecb63364SZhanjun Dong if (n) {
870ecb63364SZhanjun Dong n->locked = 0;
871ecb63364SZhanjun Dong list_del(&n->link);
872ecb63364SZhanjun Dong /* put node back to cache list */
873ecb63364SZhanjun Dong guc_capture_add_node_to_cachelist(gc, n);
874ecb63364SZhanjun Dong }
875ecb63364SZhanjun Dong }
876ecb63364SZhanjun Dong
877ecb63364SZhanjun Dong static void
guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture * gc,struct __guc_capture_parsed_output * node)878ecb63364SZhanjun Dong guc_capture_remove_stale_matches_from_list(struct xe_guc_state_capture *gc,
879ecb63364SZhanjun Dong struct __guc_capture_parsed_output *node)
880ecb63364SZhanjun Dong {
881ecb63364SZhanjun Dong struct __guc_capture_parsed_output *n, *ntmp;
882ecb63364SZhanjun Dong int guc_id = node->guc_id;
883ecb63364SZhanjun Dong
884ecb63364SZhanjun Dong list_for_each_entry_safe(n, ntmp, &gc->outlist, link) {
885ecb63364SZhanjun Dong if (n != node && !n->locked && n->guc_id == guc_id)
886ecb63364SZhanjun Dong guc_capture_free_outlist_node(gc, n);
887ecb63364SZhanjun Dong }
888ecb63364SZhanjun Dong }
889ecb63364SZhanjun Dong
890ecb63364SZhanjun Dong static void
guc_capture_init_node(struct xe_guc * guc,struct __guc_capture_parsed_output * node)8918bfc4963SZhanjun Dong guc_capture_init_node(struct xe_guc *guc, struct __guc_capture_parsed_output *node)
8928bfc4963SZhanjun Dong {
8938bfc4963SZhanjun Dong struct guc_mmio_reg *tmp[GUC_STATE_CAPTURE_TYPE_MAX];
8948bfc4963SZhanjun Dong int i;
8958bfc4963SZhanjun Dong
8968bfc4963SZhanjun Dong for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
8978bfc4963SZhanjun Dong tmp[i] = node->reginfo[i].regs;
8988bfc4963SZhanjun Dong memset(tmp[i], 0, sizeof(struct guc_mmio_reg) *
8998bfc4963SZhanjun Dong guc->capture->max_mmio_per_node);
9008bfc4963SZhanjun Dong }
9018bfc4963SZhanjun Dong memset(node, 0, sizeof(*node));
9028bfc4963SZhanjun Dong for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i)
9038bfc4963SZhanjun Dong node->reginfo[i].regs = tmp[i];
9048bfc4963SZhanjun Dong
9058bfc4963SZhanjun Dong INIT_LIST_HEAD(&node->link);
9068bfc4963SZhanjun Dong }
9078bfc4963SZhanjun Dong
9088bfc4963SZhanjun Dong /**
9098bfc4963SZhanjun Dong * DOC: Init, G2H-event and reporting flows for GuC-error-capture
9108bfc4963SZhanjun Dong *
9118bfc4963SZhanjun Dong * KMD Init time flows:
9128bfc4963SZhanjun Dong * --------------------
9138bfc4963SZhanjun Dong * --> alloc A: GuC input capture regs lists (registered to GuC via ADS).
9148bfc4963SZhanjun Dong * xe_guc_ads acquires the register lists by calling
9158bfc4963SZhanjun Dong * xe_guc_capture_getlistsize and xe_guc_capture_getlist 'n' times,
9168bfc4963SZhanjun Dong * where n = 1 for global-reg-list +
9178bfc4963SZhanjun Dong * num_engine_classes for class-reg-list +
9188bfc4963SZhanjun Dong * num_engine_classes for instance-reg-list
9198bfc4963SZhanjun Dong * (since all instances of the same engine-class type
9208bfc4963SZhanjun Dong * have an identical engine-instance register-list).
9218bfc4963SZhanjun Dong * ADS module also calls separately for PF vs VF.
9228bfc4963SZhanjun Dong *
9238bfc4963SZhanjun Dong * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param))
9248bfc4963SZhanjun Dong * Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small)
9258bfc4963SZhanjun Dong * Note2: 'x 3' to hold multiple capture groups
9268bfc4963SZhanjun Dong *
9278bfc4963SZhanjun Dong * GUC Runtime notify capture:
9288bfc4963SZhanjun Dong * --------------------------
9298bfc4963SZhanjun Dong * --> G2H STATE_CAPTURE_NOTIFICATION
9308bfc4963SZhanjun Dong * L--> xe_guc_capture_process
9318bfc4963SZhanjun Dong * L--> Loop through B (head..tail) and for each engine instance's
9328bfc4963SZhanjun Dong * err-state-captured register-list we find, we alloc 'C':
9338bfc4963SZhanjun Dong * --> alloc C: A capture-output-node structure that includes misc capture info along
9348bfc4963SZhanjun Dong * with 3 register list dumps (global, engine-class and engine-instance)
9358bfc4963SZhanjun Dong * This node is created from a pre-allocated list of blank nodes in
9368bfc4963SZhanjun Dong * guc->capture->cachelist and populated with the error-capture
9378bfc4963SZhanjun Dong * data from GuC and then it's added into guc->capture->outlist linked
9388bfc4963SZhanjun Dong * list. This list is used for matchup and printout by xe_devcoredump_read
9390f1fdf55SZhanjun Dong * and xe_engine_snapshot_print, (when user invokes the devcoredump sysfs).
9408bfc4963SZhanjun Dong *
9418bfc4963SZhanjun Dong * GUC --> notify context reset:
9428bfc4963SZhanjun Dong * -----------------------------
9438bfc4963SZhanjun Dong * --> guc_exec_queue_timedout_job
9448bfc4963SZhanjun Dong * L--> xe_devcoredump
9458bfc4963SZhanjun Dong * L--> devcoredump_snapshot
9468bfc4963SZhanjun Dong * --> xe_hw_engine_snapshot_capture
9470f1fdf55SZhanjun Dong * --> xe_engine_manual_capture(For manual capture)
9488bfc4963SZhanjun Dong *
9498bfc4963SZhanjun Dong * User Sysfs / Debugfs
9508bfc4963SZhanjun Dong * --------------------
9518bfc4963SZhanjun Dong * --> xe_devcoredump_read->
9528bfc4963SZhanjun Dong * L--> xxx_snapshot_print
9530f1fdf55SZhanjun Dong * L--> xe_engine_snapshot_print
9548bfc4963SZhanjun Dong * Print register lists values saved at
9558bfc4963SZhanjun Dong * guc->capture->outlist
9568bfc4963SZhanjun Dong *
9578bfc4963SZhanjun Dong */
9588bfc4963SZhanjun Dong
guc_capture_buf_cnt(struct __guc_capture_bufstate * buf)9598bfc4963SZhanjun Dong static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf)
9608bfc4963SZhanjun Dong {
9618bfc4963SZhanjun Dong if (buf->wr >= buf->rd)
9628bfc4963SZhanjun Dong return (buf->wr - buf->rd);
9638bfc4963SZhanjun Dong return (buf->size - buf->rd) + buf->wr;
9648bfc4963SZhanjun Dong }
9658bfc4963SZhanjun Dong
guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate * buf)9668bfc4963SZhanjun Dong static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf)
9678bfc4963SZhanjun Dong {
9688bfc4963SZhanjun Dong if (buf->rd > buf->wr)
9698bfc4963SZhanjun Dong return (buf->size - buf->rd);
9708bfc4963SZhanjun Dong return (buf->wr - buf->rd);
9718bfc4963SZhanjun Dong }
9728bfc4963SZhanjun Dong
9738bfc4963SZhanjun Dong /*
9748bfc4963SZhanjun Dong * GuC's error-capture output is a ring buffer populated in a byte-stream fashion:
9758bfc4963SZhanjun Dong *
9768bfc4963SZhanjun Dong * The GuC Log buffer region for error-capture is managed like a ring buffer.
9778bfc4963SZhanjun Dong * The GuC firmware dumps error capture logs into this ring in a byte-stream flow.
9788bfc4963SZhanjun Dong * Additionally, as per the current and foreseeable future, all packed error-
9798bfc4963SZhanjun Dong * capture output structures are dword aligned.
9808bfc4963SZhanjun Dong *
9818bfc4963SZhanjun Dong * That said, if the GuC firmware is in the midst of writing a structure that is larger
9828bfc4963SZhanjun Dong * than one dword but the tail end of the err-capture buffer-region has lesser space left,
9838bfc4963SZhanjun Dong * we would need to extract that structure one dword at a time straddled across the end,
9848bfc4963SZhanjun Dong * onto the start of the ring.
9858bfc4963SZhanjun Dong *
9868bfc4963SZhanjun Dong * Below function, guc_capture_log_remove_bytes is a helper for that. All callers of this
9878bfc4963SZhanjun Dong * function would typically do a straight-up memcpy from the ring contents and will only
9888bfc4963SZhanjun Dong * call this helper if their structure-extraction is straddling across the end of the
9898bfc4963SZhanjun Dong * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease
9908bfc4963SZhanjun Dong * scalability for future expansion of output data types without requiring a redesign
9918bfc4963SZhanjun Dong * of the flow controls.
9928bfc4963SZhanjun Dong */
9938bfc4963SZhanjun Dong static int
guc_capture_log_remove_bytes(struct xe_guc * guc,struct __guc_capture_bufstate * buf,void * out,int bytes_needed)9948bfc4963SZhanjun Dong guc_capture_log_remove_bytes(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
9958bfc4963SZhanjun Dong void *out, int bytes_needed)
9968bfc4963SZhanjun Dong {
9978bfc4963SZhanjun Dong #define GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX 3
9988bfc4963SZhanjun Dong
9998bfc4963SZhanjun Dong int fill_size = 0, tries = GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX;
10008bfc4963SZhanjun Dong int copy_size, avail;
10018bfc4963SZhanjun Dong
10028bfc4963SZhanjun Dong xe_assert(guc_to_xe(guc), bytes_needed % sizeof(u32) == 0);
10038bfc4963SZhanjun Dong
10048bfc4963SZhanjun Dong if (bytes_needed > guc_capture_buf_cnt(buf))
10058bfc4963SZhanjun Dong return -1;
10068bfc4963SZhanjun Dong
10078bfc4963SZhanjun Dong while (bytes_needed > 0 && tries--) {
10088bfc4963SZhanjun Dong int misaligned;
10098bfc4963SZhanjun Dong
10108bfc4963SZhanjun Dong avail = guc_capture_buf_cnt_to_end(buf);
10118bfc4963SZhanjun Dong misaligned = avail % sizeof(u32);
10128bfc4963SZhanjun Dong /* wrap if at end */
10138bfc4963SZhanjun Dong if (!avail) {
10148bfc4963SZhanjun Dong /* output stream clipped */
10158bfc4963SZhanjun Dong if (!buf->rd)
10168bfc4963SZhanjun Dong return fill_size;
10178bfc4963SZhanjun Dong buf->rd = 0;
10188bfc4963SZhanjun Dong continue;
10198bfc4963SZhanjun Dong }
10208bfc4963SZhanjun Dong
10218bfc4963SZhanjun Dong /* Only copy to u32 aligned data */
10228bfc4963SZhanjun Dong copy_size = avail < bytes_needed ? avail - misaligned : bytes_needed;
10238bfc4963SZhanjun Dong xe_map_memcpy_from(guc_to_xe(guc), out + fill_size, &guc->log.bo->vmap,
10248bfc4963SZhanjun Dong buf->data_offset + buf->rd, copy_size);
10258bfc4963SZhanjun Dong buf->rd += copy_size;
10268bfc4963SZhanjun Dong fill_size += copy_size;
10278bfc4963SZhanjun Dong bytes_needed -= copy_size;
10288bfc4963SZhanjun Dong
10298bfc4963SZhanjun Dong if (misaligned)
10308bfc4963SZhanjun Dong xe_gt_warn(guc_to_gt(guc),
10318bfc4963SZhanjun Dong "Bytes extraction not dword aligned, clipping.\n");
10328bfc4963SZhanjun Dong }
10338bfc4963SZhanjun Dong
10348bfc4963SZhanjun Dong return fill_size;
10358bfc4963SZhanjun Dong }
10368bfc4963SZhanjun Dong
10378bfc4963SZhanjun Dong 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)10388bfc4963SZhanjun Dong guc_capture_log_get_group_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
10398bfc4963SZhanjun Dong struct guc_state_capture_group_header_t *ghdr)
10408bfc4963SZhanjun Dong {
10418bfc4963SZhanjun Dong int fullsize = sizeof(struct guc_state_capture_group_header_t);
10428bfc4963SZhanjun Dong
10438bfc4963SZhanjun Dong if (guc_capture_log_remove_bytes(guc, buf, ghdr, fullsize) != fullsize)
10448bfc4963SZhanjun Dong return -1;
10458bfc4963SZhanjun Dong return 0;
10468bfc4963SZhanjun Dong }
10478bfc4963SZhanjun Dong
10488bfc4963SZhanjun Dong static int
guc_capture_log_get_data_hdr(struct xe_guc * guc,struct __guc_capture_bufstate * buf,struct guc_state_capture_header_t * hdr)10498bfc4963SZhanjun Dong guc_capture_log_get_data_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
10508bfc4963SZhanjun Dong struct guc_state_capture_header_t *hdr)
10518bfc4963SZhanjun Dong {
10528bfc4963SZhanjun Dong int fullsize = sizeof(struct guc_state_capture_header_t);
10538bfc4963SZhanjun Dong
10548bfc4963SZhanjun Dong if (guc_capture_log_remove_bytes(guc, buf, hdr, fullsize) != fullsize)
10558bfc4963SZhanjun Dong return -1;
10568bfc4963SZhanjun Dong return 0;
10578bfc4963SZhanjun Dong }
10588bfc4963SZhanjun Dong
10598bfc4963SZhanjun Dong static int
guc_capture_log_get_register(struct xe_guc * guc,struct __guc_capture_bufstate * buf,struct guc_mmio_reg * reg)10608bfc4963SZhanjun Dong guc_capture_log_get_register(struct xe_guc *guc, struct __guc_capture_bufstate *buf,
10618bfc4963SZhanjun Dong struct guc_mmio_reg *reg)
10628bfc4963SZhanjun Dong {
10638bfc4963SZhanjun Dong int fullsize = sizeof(struct guc_mmio_reg);
10648bfc4963SZhanjun Dong
10658bfc4963SZhanjun Dong if (guc_capture_log_remove_bytes(guc, buf, reg, fullsize) != fullsize)
10668bfc4963SZhanjun Dong return -1;
10678bfc4963SZhanjun Dong return 0;
10688bfc4963SZhanjun Dong }
10698bfc4963SZhanjun Dong
10708bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
guc_capture_get_prealloc_node(struct xe_guc * guc)10718bfc4963SZhanjun Dong guc_capture_get_prealloc_node(struct xe_guc *guc)
10728bfc4963SZhanjun Dong {
10738bfc4963SZhanjun Dong struct __guc_capture_parsed_output *found = NULL;
10748bfc4963SZhanjun Dong
10758bfc4963SZhanjun Dong if (!list_empty(&guc->capture->cachelist)) {
10768bfc4963SZhanjun Dong struct __guc_capture_parsed_output *n, *ntmp;
10778bfc4963SZhanjun Dong
10788bfc4963SZhanjun Dong /* get first avail node from the cache list */
10798bfc4963SZhanjun Dong list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) {
10808bfc4963SZhanjun Dong found = n;
10818bfc4963SZhanjun Dong break;
10828bfc4963SZhanjun Dong }
10838bfc4963SZhanjun Dong } else {
10848bfc4963SZhanjun Dong struct __guc_capture_parsed_output *n, *ntmp;
10858bfc4963SZhanjun Dong
1086ecb63364SZhanjun Dong /*
1087ecb63364SZhanjun Dong * traverse reversed and steal back the oldest node already
1088ecb63364SZhanjun Dong * allocated
1089ecb63364SZhanjun Dong */
1090ecb63364SZhanjun Dong list_for_each_entry_safe_reverse(n, ntmp, &guc->capture->outlist, link) {
1091ecb63364SZhanjun Dong if (!n->locked)
10928bfc4963SZhanjun Dong found = n;
10938bfc4963SZhanjun Dong }
10948bfc4963SZhanjun Dong }
10958bfc4963SZhanjun Dong if (found) {
10968bfc4963SZhanjun Dong list_del(&found->link);
10978bfc4963SZhanjun Dong guc_capture_init_node(guc, found);
10988bfc4963SZhanjun Dong }
10998bfc4963SZhanjun Dong
11008bfc4963SZhanjun Dong return found;
11018bfc4963SZhanjun Dong }
11028bfc4963SZhanjun Dong
11038bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
guc_capture_clone_node(struct xe_guc * guc,struct __guc_capture_parsed_output * original,u32 keep_reglist_mask)11048bfc4963SZhanjun Dong guc_capture_clone_node(struct xe_guc *guc, struct __guc_capture_parsed_output *original,
11058bfc4963SZhanjun Dong u32 keep_reglist_mask)
11068bfc4963SZhanjun Dong {
11078bfc4963SZhanjun Dong struct __guc_capture_parsed_output *new;
11088bfc4963SZhanjun Dong int i;
11098bfc4963SZhanjun Dong
11108bfc4963SZhanjun Dong new = guc_capture_get_prealloc_node(guc);
11118bfc4963SZhanjun Dong if (!new)
11128bfc4963SZhanjun Dong return NULL;
11138bfc4963SZhanjun Dong if (!original)
11148bfc4963SZhanjun Dong return new;
11158bfc4963SZhanjun Dong
11168bfc4963SZhanjun Dong new->is_partial = original->is_partial;
11178bfc4963SZhanjun Dong
11188bfc4963SZhanjun Dong /* copy reg-lists that we want to clone */
11198bfc4963SZhanjun Dong for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
11208bfc4963SZhanjun Dong if (keep_reglist_mask & BIT(i)) {
11218bfc4963SZhanjun Dong XE_WARN_ON(original->reginfo[i].num_regs >
11228bfc4963SZhanjun Dong guc->capture->max_mmio_per_node);
11238bfc4963SZhanjun Dong
11248bfc4963SZhanjun Dong memcpy(new->reginfo[i].regs, original->reginfo[i].regs,
11258bfc4963SZhanjun Dong original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg));
11268bfc4963SZhanjun Dong
11278bfc4963SZhanjun Dong new->reginfo[i].num_regs = original->reginfo[i].num_regs;
11288bfc4963SZhanjun Dong new->reginfo[i].vfid = original->reginfo[i].vfid;
11298bfc4963SZhanjun Dong
11308bfc4963SZhanjun Dong if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) {
11318bfc4963SZhanjun Dong new->eng_class = original->eng_class;
11328bfc4963SZhanjun Dong } else if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
11338bfc4963SZhanjun Dong new->eng_inst = original->eng_inst;
11348bfc4963SZhanjun Dong new->guc_id = original->guc_id;
11358bfc4963SZhanjun Dong new->lrca = original->lrca;
11368bfc4963SZhanjun Dong }
11378bfc4963SZhanjun Dong }
11388bfc4963SZhanjun Dong }
11398bfc4963SZhanjun Dong
11408bfc4963SZhanjun Dong return new;
11418bfc4963SZhanjun Dong }
11428bfc4963SZhanjun Dong
11438bfc4963SZhanjun Dong static int
guc_capture_extract_reglists(struct xe_guc * guc,struct __guc_capture_bufstate * buf)11448bfc4963SZhanjun Dong guc_capture_extract_reglists(struct xe_guc *guc, struct __guc_capture_bufstate *buf)
11458bfc4963SZhanjun Dong {
11468bfc4963SZhanjun Dong struct xe_gt *gt = guc_to_gt(guc);
11478bfc4963SZhanjun Dong struct guc_state_capture_group_header_t ghdr = {0};
11488bfc4963SZhanjun Dong struct guc_state_capture_header_t hdr = {0};
11498bfc4963SZhanjun Dong struct __guc_capture_parsed_output *node = NULL;
11508bfc4963SZhanjun Dong struct guc_mmio_reg *regs = NULL;
11518bfc4963SZhanjun Dong int i, numlists, numregs, ret = 0;
11528bfc4963SZhanjun Dong enum guc_state_capture_type datatype;
11538bfc4963SZhanjun Dong struct guc_mmio_reg tmp;
11548bfc4963SZhanjun Dong bool is_partial = false;
11558bfc4963SZhanjun Dong
11568bfc4963SZhanjun Dong i = guc_capture_buf_cnt(buf);
11578bfc4963SZhanjun Dong if (!i)
11588bfc4963SZhanjun Dong return -ENODATA;
11598bfc4963SZhanjun Dong
11608bfc4963SZhanjun Dong if (i % sizeof(u32)) {
11618bfc4963SZhanjun Dong xe_gt_warn(gt, "Got mis-aligned register capture entries\n");
11628bfc4963SZhanjun Dong ret = -EIO;
11638bfc4963SZhanjun Dong goto bailout;
11648bfc4963SZhanjun Dong }
11658bfc4963SZhanjun Dong
11668bfc4963SZhanjun Dong /* first get the capture group header */
11678bfc4963SZhanjun Dong if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) {
11688bfc4963SZhanjun Dong ret = -EIO;
11698bfc4963SZhanjun Dong goto bailout;
11708bfc4963SZhanjun Dong }
11718bfc4963SZhanjun Dong /*
11728bfc4963SZhanjun Dong * we would typically expect a layout as below where n would be expected to be
11738bfc4963SZhanjun Dong * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine
11748bfc4963SZhanjun Dong * instances being reset together.
11758bfc4963SZhanjun Dong * ____________________________________________
11768bfc4963SZhanjun Dong * | Capture Group |
11778bfc4963SZhanjun Dong * | ________________________________________ |
11788bfc4963SZhanjun Dong * | | Capture Group Header: | |
11798bfc4963SZhanjun Dong * | | - num_captures = 5 | |
11808bfc4963SZhanjun Dong * | |______________________________________| |
11818bfc4963SZhanjun Dong * | ________________________________________ |
11828bfc4963SZhanjun Dong * | | Capture1: | |
11838bfc4963SZhanjun Dong * | | Hdr: GLOBAL, numregs=a | |
11848bfc4963SZhanjun Dong * | | ____________________________________ | |
11858bfc4963SZhanjun Dong * | | | Reglist | | |
11868bfc4963SZhanjun Dong * | | | - reg1, reg2, ... rega | | |
11878bfc4963SZhanjun Dong * | | |__________________________________| | |
11888bfc4963SZhanjun Dong * | |______________________________________| |
11898bfc4963SZhanjun Dong * | ________________________________________ |
11908bfc4963SZhanjun Dong * | | Capture2: | |
11918bfc4963SZhanjun Dong * | | Hdr: CLASS=RENDER/COMPUTE, numregs=b| |
11928bfc4963SZhanjun Dong * | | ____________________________________ | |
11938bfc4963SZhanjun Dong * | | | Reglist | | |
11948bfc4963SZhanjun Dong * | | | - reg1, reg2, ... regb | | |
11958bfc4963SZhanjun Dong * | | |__________________________________| | |
11968bfc4963SZhanjun Dong * | |______________________________________| |
11978bfc4963SZhanjun Dong * | ________________________________________ |
11988bfc4963SZhanjun Dong * | | Capture3: | |
11998bfc4963SZhanjun Dong * | | Hdr: INSTANCE=RCS, numregs=c | |
12008bfc4963SZhanjun Dong * | | ____________________________________ | |
12018bfc4963SZhanjun Dong * | | | Reglist | | |
12028bfc4963SZhanjun Dong * | | | - reg1, reg2, ... regc | | |
12038bfc4963SZhanjun Dong * | | |__________________________________| | |
12048bfc4963SZhanjun Dong * | |______________________________________| |
12058bfc4963SZhanjun Dong * | ________________________________________ |
12068bfc4963SZhanjun Dong * | | Capture4: | |
12078bfc4963SZhanjun Dong * | | Hdr: CLASS=RENDER/COMPUTE, numregs=d| |
12088bfc4963SZhanjun Dong * | | ____________________________________ | |
12098bfc4963SZhanjun Dong * | | | Reglist | | |
12108bfc4963SZhanjun Dong * | | | - reg1, reg2, ... regd | | |
12118bfc4963SZhanjun Dong * | | |__________________________________| | |
12128bfc4963SZhanjun Dong * | |______________________________________| |
12138bfc4963SZhanjun Dong * | ________________________________________ |
12148bfc4963SZhanjun Dong * | | Capture5: | |
12158bfc4963SZhanjun Dong * | | Hdr: INSTANCE=CCS0, numregs=e | |
12168bfc4963SZhanjun Dong * | | ____________________________________ | |
12178bfc4963SZhanjun Dong * | | | Reglist | | |
12188bfc4963SZhanjun Dong * | | | - reg1, reg2, ... rege | | |
12198bfc4963SZhanjun Dong * | | |__________________________________| | |
12208bfc4963SZhanjun Dong * | |______________________________________| |
12218bfc4963SZhanjun Dong * |__________________________________________|
12228bfc4963SZhanjun Dong */
12238bfc4963SZhanjun Dong is_partial = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE, ghdr.info);
12248bfc4963SZhanjun Dong numlists = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES, ghdr.info);
12258bfc4963SZhanjun Dong
12268bfc4963SZhanjun Dong while (numlists--) {
12278bfc4963SZhanjun Dong if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) {
12288bfc4963SZhanjun Dong ret = -EIO;
12298bfc4963SZhanjun Dong break;
12308bfc4963SZhanjun Dong }
12318bfc4963SZhanjun Dong
12328bfc4963SZhanjun Dong datatype = FIELD_GET(GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE, hdr.info);
12338bfc4963SZhanjun Dong if (datatype > GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
12348bfc4963SZhanjun Dong /* unknown capture type - skip over to next capture set */
12358bfc4963SZhanjun Dong numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
12368bfc4963SZhanjun Dong hdr.num_mmio_entries);
12378bfc4963SZhanjun Dong while (numregs--) {
12388bfc4963SZhanjun Dong if (guc_capture_log_get_register(guc, buf, &tmp)) {
12398bfc4963SZhanjun Dong ret = -EIO;
12408bfc4963SZhanjun Dong break;
12418bfc4963SZhanjun Dong }
12428bfc4963SZhanjun Dong }
12438bfc4963SZhanjun Dong continue;
12448bfc4963SZhanjun Dong } else if (node) {
12458bfc4963SZhanjun Dong /*
12468bfc4963SZhanjun Dong * Based on the current capture type and what we have so far,
12478bfc4963SZhanjun Dong * decide if we should add the current node into the internal
12488bfc4963SZhanjun Dong * linked list for match-up when xe_devcoredump calls later
12498bfc4963SZhanjun Dong * (and alloc a blank node for the next set of reglists)
12508bfc4963SZhanjun Dong * or continue with the same node or clone the current node
12518bfc4963SZhanjun Dong * but only retain the global or class registers (such as the
12528bfc4963SZhanjun Dong * case of dependent engine resets).
12538bfc4963SZhanjun Dong */
12548bfc4963SZhanjun Dong if (datatype == GUC_STATE_CAPTURE_TYPE_GLOBAL) {
12558bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(guc->capture, node);
12568bfc4963SZhanjun Dong node = NULL;
12578bfc4963SZhanjun Dong } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
12588bfc4963SZhanjun Dong node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS].num_regs) {
12598bfc4963SZhanjun Dong /* Add to list, clone node and duplicate global list */
12608bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(guc->capture, node);
12618bfc4963SZhanjun Dong node = guc_capture_clone_node(guc, node,
12628bfc4963SZhanjun Dong GCAP_PARSED_REGLIST_INDEX_GLOBAL);
12638bfc4963SZhanjun Dong } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE &&
12648bfc4963SZhanjun Dong node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE].num_regs) {
12658bfc4963SZhanjun Dong /* Add to list, clone node and duplicate global + class lists */
12668bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(guc->capture, node);
12678bfc4963SZhanjun Dong node = guc_capture_clone_node(guc, node,
12688bfc4963SZhanjun Dong (GCAP_PARSED_REGLIST_INDEX_GLOBAL |
12698bfc4963SZhanjun Dong GCAP_PARSED_REGLIST_INDEX_ENGCLASS));
12708bfc4963SZhanjun Dong }
12718bfc4963SZhanjun Dong }
12728bfc4963SZhanjun Dong
12738bfc4963SZhanjun Dong if (!node) {
12748bfc4963SZhanjun Dong node = guc_capture_get_prealloc_node(guc);
12758bfc4963SZhanjun Dong if (!node) {
12768bfc4963SZhanjun Dong ret = -ENOMEM;
12778bfc4963SZhanjun Dong break;
12788bfc4963SZhanjun Dong }
12798bfc4963SZhanjun Dong if (datatype != GUC_STATE_CAPTURE_TYPE_GLOBAL)
12808bfc4963SZhanjun Dong xe_gt_dbg(gt, "Register capture missing global dump: %08x!\n",
12818bfc4963SZhanjun Dong datatype);
12828bfc4963SZhanjun Dong }
12838bfc4963SZhanjun Dong node->is_partial = is_partial;
12848bfc4963SZhanjun Dong node->reginfo[datatype].vfid = FIELD_GET(GUC_STATE_CAPTURE_HEADER_VFID, hdr.owner);
1285ecb63364SZhanjun Dong node->source = XE_ENGINE_CAPTURE_SOURCE_GUC;
1286ecb63364SZhanjun Dong node->type = datatype;
12878bfc4963SZhanjun Dong
12888bfc4963SZhanjun Dong switch (datatype) {
12898bfc4963SZhanjun Dong case GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE:
12908bfc4963SZhanjun Dong node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
12918bfc4963SZhanjun Dong hdr.info);
12928bfc4963SZhanjun Dong node->eng_inst = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE,
12938bfc4963SZhanjun Dong hdr.info);
12948bfc4963SZhanjun Dong node->lrca = hdr.lrca;
12958bfc4963SZhanjun Dong node->guc_id = hdr.guc_id;
12968bfc4963SZhanjun Dong break;
12978bfc4963SZhanjun Dong case GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS:
12988bfc4963SZhanjun Dong node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS,
12998bfc4963SZhanjun Dong hdr.info);
13008bfc4963SZhanjun Dong break;
13018bfc4963SZhanjun Dong default:
13028bfc4963SZhanjun Dong break;
13038bfc4963SZhanjun Dong }
13048bfc4963SZhanjun Dong
13058bfc4963SZhanjun Dong numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES,
13068bfc4963SZhanjun Dong hdr.num_mmio_entries);
13078bfc4963SZhanjun Dong if (numregs > guc->capture->max_mmio_per_node) {
13088bfc4963SZhanjun Dong xe_gt_dbg(gt, "Register capture list extraction clipped by prealloc!\n");
13098bfc4963SZhanjun Dong numregs = guc->capture->max_mmio_per_node;
13108bfc4963SZhanjun Dong }
13118bfc4963SZhanjun Dong node->reginfo[datatype].num_regs = numregs;
13128bfc4963SZhanjun Dong regs = node->reginfo[datatype].regs;
13138bfc4963SZhanjun Dong i = 0;
13148bfc4963SZhanjun Dong while (numregs--) {
13158bfc4963SZhanjun Dong if (guc_capture_log_get_register(guc, buf, ®s[i++])) {
13168bfc4963SZhanjun Dong ret = -EIO;
13178bfc4963SZhanjun Dong break;
13188bfc4963SZhanjun Dong }
13198bfc4963SZhanjun Dong }
13208bfc4963SZhanjun Dong }
13218bfc4963SZhanjun Dong
13228bfc4963SZhanjun Dong bailout:
13238bfc4963SZhanjun Dong if (node) {
13248bfc4963SZhanjun Dong /* If we have data, add to linked list for match-up when xe_devcoredump calls */
13258bfc4963SZhanjun Dong for (i = GUC_STATE_CAPTURE_TYPE_GLOBAL; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
13268bfc4963SZhanjun Dong if (node->reginfo[i].regs) {
13278bfc4963SZhanjun Dong guc_capture_add_node_to_outlist(guc->capture, node);
13288bfc4963SZhanjun Dong node = NULL;
13298bfc4963SZhanjun Dong break;
13308bfc4963SZhanjun Dong }
13318bfc4963SZhanjun Dong }
13328bfc4963SZhanjun Dong if (node) /* else return it back to cache list */
13338bfc4963SZhanjun Dong guc_capture_add_node_to_cachelist(guc->capture, node);
13348bfc4963SZhanjun Dong }
13358bfc4963SZhanjun Dong return ret;
13368bfc4963SZhanjun Dong }
13378bfc4963SZhanjun Dong
__guc_capture_flushlog_complete(struct xe_guc * guc)13388bfc4963SZhanjun Dong static int __guc_capture_flushlog_complete(struct xe_guc *guc)
13398bfc4963SZhanjun Dong {
13408bfc4963SZhanjun Dong u32 action[] = {
13418bfc4963SZhanjun Dong XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE,
13428bfc4963SZhanjun Dong GUC_LOG_BUFFER_CAPTURE
13438bfc4963SZhanjun Dong };
13448bfc4963SZhanjun Dong
13458bfc4963SZhanjun Dong return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action));
13468bfc4963SZhanjun Dong }
13478bfc4963SZhanjun Dong
__guc_capture_process_output(struct xe_guc * guc)13488bfc4963SZhanjun Dong static void __guc_capture_process_output(struct xe_guc *guc)
13498bfc4963SZhanjun Dong {
13508bfc4963SZhanjun Dong unsigned int buffer_size, read_offset, write_offset, full_count;
13518bfc4963SZhanjun Dong struct xe_uc *uc = container_of(guc, typeof(*uc), guc);
13528bfc4963SZhanjun Dong struct guc_log_buffer_state log_buf_state_local;
13538bfc4963SZhanjun Dong struct __guc_capture_bufstate buf;
13548bfc4963SZhanjun Dong bool new_overflow;
13558bfc4963SZhanjun Dong int ret, tmp;
13568bfc4963SZhanjun Dong u32 log_buf_state_offset;
13578bfc4963SZhanjun Dong u32 src_data_offset;
13588bfc4963SZhanjun Dong
13598bfc4963SZhanjun Dong log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_BUFFER_CAPTURE;
13608bfc4963SZhanjun Dong src_data_offset = xe_guc_get_log_buffer_offset(&guc->log, GUC_LOG_BUFFER_CAPTURE);
13618bfc4963SZhanjun Dong
13628bfc4963SZhanjun Dong /*
13638bfc4963SZhanjun Dong * Make a copy of the state structure, inside GuC log buffer
13648bfc4963SZhanjun Dong * (which is uncached mapped), on the stack to avoid reading
13658bfc4963SZhanjun Dong * from it multiple times.
13668bfc4963SZhanjun Dong */
13678bfc4963SZhanjun Dong xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap,
13688bfc4963SZhanjun Dong log_buf_state_offset, sizeof(struct guc_log_buffer_state));
13698bfc4963SZhanjun Dong
13708bfc4963SZhanjun Dong buffer_size = xe_guc_get_log_buffer_size(&guc->log, GUC_LOG_BUFFER_CAPTURE);
13718bfc4963SZhanjun Dong read_offset = log_buf_state_local.read_ptr;
13728bfc4963SZhanjun Dong write_offset = log_buf_state_local.sampled_write_ptr;
13738bfc4963SZhanjun Dong full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags);
13748bfc4963SZhanjun Dong
13758bfc4963SZhanjun Dong /* Bookkeeping stuff */
13768bfc4963SZhanjun Dong tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags);
13778bfc4963SZhanjun Dong guc->log.stats[GUC_LOG_BUFFER_CAPTURE].flush += tmp;
13788bfc4963SZhanjun Dong new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_BUFFER_CAPTURE,
13798bfc4963SZhanjun Dong full_count);
13808bfc4963SZhanjun Dong
13818bfc4963SZhanjun Dong /* Now copy the actual logs. */
13828bfc4963SZhanjun Dong if (unlikely(new_overflow)) {
13838bfc4963SZhanjun Dong /* copy the whole buffer in case of overflow */
13848bfc4963SZhanjun Dong read_offset = 0;
13858bfc4963SZhanjun Dong write_offset = buffer_size;
13868bfc4963SZhanjun Dong } else if (unlikely((read_offset > buffer_size) ||
13878bfc4963SZhanjun Dong (write_offset > buffer_size))) {
13888bfc4963SZhanjun Dong xe_gt_err(guc_to_gt(guc),
13898bfc4963SZhanjun Dong "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n",
13908bfc4963SZhanjun Dong read_offset, buffer_size);
13918bfc4963SZhanjun Dong /* copy whole buffer as offsets are unreliable */
13928bfc4963SZhanjun Dong read_offset = 0;
13938bfc4963SZhanjun Dong write_offset = buffer_size;
13948bfc4963SZhanjun Dong }
13958bfc4963SZhanjun Dong
13968bfc4963SZhanjun Dong buf.size = buffer_size;
13978bfc4963SZhanjun Dong buf.rd = read_offset;
13988bfc4963SZhanjun Dong buf.wr = write_offset;
13998bfc4963SZhanjun Dong buf.data_offset = src_data_offset;
14008bfc4963SZhanjun Dong
14018bfc4963SZhanjun Dong if (!xe_guc_read_stopped(guc)) {
14028bfc4963SZhanjun Dong do {
14038bfc4963SZhanjun Dong ret = guc_capture_extract_reglists(guc, &buf);
14048bfc4963SZhanjun Dong if (ret && ret != -ENODATA)
14058bfc4963SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "Capture extraction failed:%d\n", ret);
14068bfc4963SZhanjun Dong } while (ret >= 0);
14078bfc4963SZhanjun Dong }
14088bfc4963SZhanjun Dong
14098bfc4963SZhanjun Dong /* Update the state of log buffer err-cap state */
14108bfc4963SZhanjun Dong xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
14118bfc4963SZhanjun Dong log_buf_state_offset + offsetof(struct guc_log_buffer_state, read_ptr), u32,
14128bfc4963SZhanjun Dong write_offset);
14138bfc4963SZhanjun Dong
14148bfc4963SZhanjun Dong /*
14158bfc4963SZhanjun Dong * Clear the flush_to_file from local first, the local was loaded by above
14168bfc4963SZhanjun Dong * xe_map_memcpy_from, then write out the "updated local" through
14178bfc4963SZhanjun Dong * xe_map_wr()
14188bfc4963SZhanjun Dong */
14198bfc4963SZhanjun Dong log_buf_state_local.flags &= ~GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE;
14208bfc4963SZhanjun Dong xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap,
14218bfc4963SZhanjun Dong log_buf_state_offset + offsetof(struct guc_log_buffer_state, flags), u32,
14228bfc4963SZhanjun Dong log_buf_state_local.flags);
14238bfc4963SZhanjun Dong __guc_capture_flushlog_complete(guc);
14248bfc4963SZhanjun Dong }
14258bfc4963SZhanjun Dong
14268bfc4963SZhanjun Dong /*
14278bfc4963SZhanjun Dong * xe_guc_capture_process - Process GuC register captured data
14288bfc4963SZhanjun Dong * @guc: The GuC object
14298bfc4963SZhanjun Dong *
14308bfc4963SZhanjun Dong * When GuC captured data is ready, GuC will send message
14318bfc4963SZhanjun Dong * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be
14328bfc4963SZhanjun Dong * called to process the data comes with the message.
14338bfc4963SZhanjun Dong *
14348bfc4963SZhanjun Dong * Returns: None
14358bfc4963SZhanjun Dong */
xe_guc_capture_process(struct xe_guc * guc)14368bfc4963SZhanjun Dong void xe_guc_capture_process(struct xe_guc *guc)
14378bfc4963SZhanjun Dong {
14388bfc4963SZhanjun Dong if (guc->capture)
14398bfc4963SZhanjun Dong __guc_capture_process_output(guc);
14408bfc4963SZhanjun Dong }
14418bfc4963SZhanjun Dong
14428bfc4963SZhanjun Dong static struct __guc_capture_parsed_output *
guc_capture_alloc_one_node(struct xe_guc * guc)14438bfc4963SZhanjun Dong guc_capture_alloc_one_node(struct xe_guc *guc)
14448bfc4963SZhanjun Dong {
14458bfc4963SZhanjun Dong struct drm_device *drm = guc_to_drm(guc);
14468bfc4963SZhanjun Dong struct __guc_capture_parsed_output *new;
14478bfc4963SZhanjun Dong int i;
14488bfc4963SZhanjun Dong
14498bfc4963SZhanjun Dong new = drmm_kzalloc(drm, sizeof(*new), GFP_KERNEL);
14508bfc4963SZhanjun Dong if (!new)
14518bfc4963SZhanjun Dong return NULL;
14528bfc4963SZhanjun Dong
14538bfc4963SZhanjun Dong for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) {
14548bfc4963SZhanjun Dong new->reginfo[i].regs = drmm_kzalloc(drm, guc->capture->max_mmio_per_node *
14558bfc4963SZhanjun Dong sizeof(struct guc_mmio_reg), GFP_KERNEL);
14568bfc4963SZhanjun Dong if (!new->reginfo[i].regs) {
14578bfc4963SZhanjun Dong while (i)
14588bfc4963SZhanjun Dong drmm_kfree(drm, new->reginfo[--i].regs);
14598bfc4963SZhanjun Dong drmm_kfree(drm, new);
14608bfc4963SZhanjun Dong return NULL;
14618bfc4963SZhanjun Dong }
14628bfc4963SZhanjun Dong }
14638bfc4963SZhanjun Dong guc_capture_init_node(guc, new);
14648bfc4963SZhanjun Dong
14658bfc4963SZhanjun Dong return new;
14668bfc4963SZhanjun Dong }
14678bfc4963SZhanjun Dong
14688bfc4963SZhanjun Dong static void
__guc_capture_create_prealloc_nodes(struct xe_guc * guc)14698bfc4963SZhanjun Dong __guc_capture_create_prealloc_nodes(struct xe_guc *guc)
14708bfc4963SZhanjun Dong {
14718bfc4963SZhanjun Dong struct __guc_capture_parsed_output *node = NULL;
14728bfc4963SZhanjun Dong int i;
14738bfc4963SZhanjun Dong
14748bfc4963SZhanjun Dong for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) {
14758bfc4963SZhanjun Dong node = guc_capture_alloc_one_node(guc);
14768bfc4963SZhanjun Dong if (!node) {
14778bfc4963SZhanjun Dong xe_gt_warn(guc_to_gt(guc), "Register capture pre-alloc-cache failure\n");
14788bfc4963SZhanjun Dong /* dont free the priors, use what we got and cleanup at shutdown */
14798bfc4963SZhanjun Dong return;
14808bfc4963SZhanjun Dong }
14818bfc4963SZhanjun Dong guc_capture_add_node_to_cachelist(guc->capture, node);
14828bfc4963SZhanjun Dong }
14838bfc4963SZhanjun Dong }
14848bfc4963SZhanjun Dong
14858bfc4963SZhanjun Dong static int
guc_get_max_reglist_count(struct xe_guc * guc)14868bfc4963SZhanjun Dong guc_get_max_reglist_count(struct xe_guc *guc)
14878bfc4963SZhanjun Dong {
14888bfc4963SZhanjun Dong int i, j, k, tmp, maxregcount = 0;
14898bfc4963SZhanjun Dong
14908bfc4963SZhanjun Dong for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) {
14918bfc4963SZhanjun Dong for (j = 0; j < GUC_STATE_CAPTURE_TYPE_MAX; ++j) {
14928bfc4963SZhanjun Dong for (k = 0; k < GUC_CAPTURE_LIST_CLASS_MAX; ++k) {
14938bfc4963SZhanjun Dong const struct __guc_mmio_reg_descr_group *match;
14948bfc4963SZhanjun Dong
14958bfc4963SZhanjun Dong if (j == GUC_STATE_CAPTURE_TYPE_GLOBAL && k > 0)
14968bfc4963SZhanjun Dong continue;
14978bfc4963SZhanjun Dong
14988bfc4963SZhanjun Dong tmp = 0;
14998bfc4963SZhanjun Dong match = guc_capture_get_one_list(guc->capture->reglists, i, j, k);
15008bfc4963SZhanjun Dong if (match)
15018bfc4963SZhanjun Dong tmp = match->num_regs;
15028bfc4963SZhanjun Dong
15038bfc4963SZhanjun Dong match = guc_capture_get_one_list(guc->capture->extlists, i, j, k);
15048bfc4963SZhanjun Dong if (match)
15058bfc4963SZhanjun Dong tmp += match->num_regs;
15068bfc4963SZhanjun Dong
15078bfc4963SZhanjun Dong if (tmp > maxregcount)
15088bfc4963SZhanjun Dong maxregcount = tmp;
15098bfc4963SZhanjun Dong }
15108bfc4963SZhanjun Dong }
15118bfc4963SZhanjun Dong }
15128bfc4963SZhanjun Dong if (!maxregcount)
15138bfc4963SZhanjun Dong maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS;
15148bfc4963SZhanjun Dong
15158bfc4963SZhanjun Dong return maxregcount;
15168bfc4963SZhanjun Dong }
15178bfc4963SZhanjun Dong
15188bfc4963SZhanjun Dong static void
guc_capture_create_prealloc_nodes(struct xe_guc * guc)15198bfc4963SZhanjun Dong guc_capture_create_prealloc_nodes(struct xe_guc *guc)
15208bfc4963SZhanjun Dong {
15218bfc4963SZhanjun Dong /* skip if we've already done the pre-alloc */
15228bfc4963SZhanjun Dong if (guc->capture->max_mmio_per_node)
15238bfc4963SZhanjun Dong return;
15248bfc4963SZhanjun Dong
15258bfc4963SZhanjun Dong guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc);
15268bfc4963SZhanjun Dong __guc_capture_create_prealloc_nodes(guc);
15278bfc4963SZhanjun Dong }
15288bfc4963SZhanjun Dong
15290f1fdf55SZhanjun Dong static void
read_reg_to_node(struct xe_hw_engine * hwe,const struct __guc_mmio_reg_descr_group * list,struct guc_mmio_reg * regs)15300f1fdf55SZhanjun Dong read_reg_to_node(struct xe_hw_engine *hwe, const struct __guc_mmio_reg_descr_group *list,
15310f1fdf55SZhanjun Dong struct guc_mmio_reg *regs)
15320f1fdf55SZhanjun Dong {
15330f1fdf55SZhanjun Dong int i;
15340f1fdf55SZhanjun Dong
15356d9f9115SEverest K.C. if (!list || !list->list || list->num_regs == 0)
15360f1fdf55SZhanjun Dong return;
15370f1fdf55SZhanjun Dong
15380f1fdf55SZhanjun Dong if (!regs)
15390f1fdf55SZhanjun Dong return;
15400f1fdf55SZhanjun Dong
15410f1fdf55SZhanjun Dong for (i = 0; i < list->num_regs; i++) {
15420f1fdf55SZhanjun Dong struct __guc_mmio_reg_descr desc = list->list[i];
15430f1fdf55SZhanjun Dong u32 value;
15440f1fdf55SZhanjun Dong
15450f1fdf55SZhanjun Dong if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) {
15460f1fdf55SZhanjun Dong value = xe_hw_engine_mmio_read32(hwe, desc.reg);
15470f1fdf55SZhanjun Dong } else {
15480f1fdf55SZhanjun Dong if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS &&
15490f1fdf55SZhanjun Dong FIELD_GET(GUC_REGSET_STEERING_NEEDED, desc.flags)) {
15500f1fdf55SZhanjun Dong int group, instance;
15510f1fdf55SZhanjun Dong
15520f1fdf55SZhanjun Dong group = FIELD_GET(GUC_REGSET_STEERING_GROUP, desc.flags);
15530f1fdf55SZhanjun Dong instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, desc.flags);
15540f1fdf55SZhanjun Dong value = xe_gt_mcr_unicast_read(hwe->gt, XE_REG_MCR(desc.reg.addr),
15550f1fdf55SZhanjun Dong group, instance);
15560f1fdf55SZhanjun Dong } else {
15570f1fdf55SZhanjun Dong value = xe_mmio_read32(&hwe->gt->mmio, desc.reg);
15580f1fdf55SZhanjun Dong }
15590f1fdf55SZhanjun Dong }
15600f1fdf55SZhanjun Dong
15610f1fdf55SZhanjun Dong regs[i].value = value;
15620f1fdf55SZhanjun Dong regs[i].offset = desc.reg.addr;
15630f1fdf55SZhanjun Dong regs[i].flags = desc.flags;
15640f1fdf55SZhanjun Dong regs[i].mask = desc.mask;
15650f1fdf55SZhanjun Dong }
15660f1fdf55SZhanjun Dong }
15670f1fdf55SZhanjun Dong
15680f1fdf55SZhanjun Dong /**
15690f1fdf55SZhanjun Dong * xe_engine_manual_capture - Take a manual engine snapshot from engine.
15700f1fdf55SZhanjun Dong * @hwe: Xe HW Engine.
15710f1fdf55SZhanjun Dong * @snapshot: The engine snapshot
15720f1fdf55SZhanjun Dong *
15730f1fdf55SZhanjun Dong * Take engine snapshot from engine read.
15740f1fdf55SZhanjun Dong *
15750f1fdf55SZhanjun Dong * Returns: None
15760f1fdf55SZhanjun Dong */
15770f1fdf55SZhanjun Dong void
xe_engine_manual_capture(struct xe_hw_engine * hwe,struct xe_hw_engine_snapshot * snapshot)15780f1fdf55SZhanjun Dong xe_engine_manual_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot)
15790f1fdf55SZhanjun Dong {
15800f1fdf55SZhanjun Dong struct xe_gt *gt = hwe->gt;
15810f1fdf55SZhanjun Dong struct xe_device *xe = gt_to_xe(gt);
15820f1fdf55SZhanjun Dong struct xe_guc *guc = >->uc.guc;
15830f1fdf55SZhanjun Dong struct xe_devcoredump *devcoredump = &xe->devcoredump;
15840f1fdf55SZhanjun Dong enum guc_capture_list_class_type capture_class;
15850f1fdf55SZhanjun Dong const struct __guc_mmio_reg_descr_group *list;
15860f1fdf55SZhanjun Dong struct __guc_capture_parsed_output *new;
15870f1fdf55SZhanjun Dong enum guc_state_capture_type type;
15880f1fdf55SZhanjun Dong u16 guc_id = 0;
15890f1fdf55SZhanjun Dong u32 lrca = 0;
15900f1fdf55SZhanjun Dong
1591dd1ba621SZhanjun Dong if (IS_SRIOV_VF(xe))
1592dd1ba621SZhanjun Dong return;
1593dd1ba621SZhanjun Dong
15940f1fdf55SZhanjun Dong new = guc_capture_get_prealloc_node(guc);
15950f1fdf55SZhanjun Dong if (!new)
15960f1fdf55SZhanjun Dong return;
15970f1fdf55SZhanjun Dong
15980f1fdf55SZhanjun Dong capture_class = xe_engine_class_to_guc_capture_class(hwe->class);
15990f1fdf55SZhanjun Dong for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) {
16000f1fdf55SZhanjun Dong struct gcap_reg_list_info *reginfo = &new->reginfo[type];
16010f1fdf55SZhanjun Dong /*
16020f1fdf55SZhanjun Dong * regsinfo->regs is allocated based on guc->capture->max_mmio_per_node
16030f1fdf55SZhanjun Dong * which is based on the descriptor list driving the population so
16040f1fdf55SZhanjun Dong * should not overflow
16050f1fdf55SZhanjun Dong */
16060f1fdf55SZhanjun Dong
16070f1fdf55SZhanjun Dong /* Get register list for the type/class */
16080f1fdf55SZhanjun Dong list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type,
16090f1fdf55SZhanjun Dong capture_class, false);
16100f1fdf55SZhanjun Dong if (!list) {
16110f1fdf55SZhanjun Dong xe_gt_dbg(gt, "Empty GuC capture register descriptor for %s",
16120f1fdf55SZhanjun Dong hwe->name);
16130f1fdf55SZhanjun Dong continue;
16140f1fdf55SZhanjun Dong }
16150f1fdf55SZhanjun Dong
16160f1fdf55SZhanjun Dong read_reg_to_node(hwe, list, reginfo->regs);
16170f1fdf55SZhanjun Dong reginfo->num_regs = list->num_regs;
16180f1fdf55SZhanjun Dong
16190f1fdf55SZhanjun Dong /* Capture steering registers for rcs/ccs */
16200f1fdf55SZhanjun Dong if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
16210f1fdf55SZhanjun Dong list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF,
16220f1fdf55SZhanjun Dong type, capture_class, true);
16230f1fdf55SZhanjun Dong if (list) {
16240f1fdf55SZhanjun Dong read_reg_to_node(hwe, list, ®info->regs[reginfo->num_regs]);
16250f1fdf55SZhanjun Dong reginfo->num_regs += list->num_regs;
16260f1fdf55SZhanjun Dong }
16270f1fdf55SZhanjun Dong }
16280f1fdf55SZhanjun Dong }
16290f1fdf55SZhanjun Dong
16300f1fdf55SZhanjun Dong if (devcoredump && devcoredump->captured) {
16310f1fdf55SZhanjun Dong struct xe_guc_submit_exec_queue_snapshot *ge = devcoredump->snapshot.ge;
16320f1fdf55SZhanjun Dong
16330f1fdf55SZhanjun Dong if (ge) {
16340f1fdf55SZhanjun Dong guc_id = ge->guc.id;
16350f1fdf55SZhanjun Dong if (ge->lrc[0])
16360f1fdf55SZhanjun Dong lrca = ge->lrc[0]->context_desc;
16370f1fdf55SZhanjun Dong }
16380f1fdf55SZhanjun Dong }
16390f1fdf55SZhanjun Dong
16400f1fdf55SZhanjun Dong new->eng_class = xe_engine_class_to_guc_class(hwe->class);
16410f1fdf55SZhanjun Dong new->eng_inst = hwe->instance;
16420f1fdf55SZhanjun Dong new->guc_id = guc_id;
16430f1fdf55SZhanjun Dong new->lrca = lrca;
16440f1fdf55SZhanjun Dong new->is_partial = 0;
16450f1fdf55SZhanjun Dong new->locked = 1;
16460f1fdf55SZhanjun Dong new->source = XE_ENGINE_CAPTURE_SOURCE_MANUAL;
16470f1fdf55SZhanjun Dong
16480f1fdf55SZhanjun Dong guc_capture_add_node_to_outlist(guc->capture, new);
16490f1fdf55SZhanjun Dong devcoredump->snapshot.matched_node = new;
16500f1fdf55SZhanjun Dong }
16510f1fdf55SZhanjun Dong
1652ecb63364SZhanjun Dong static struct guc_mmio_reg *
guc_capture_find_reg(struct gcap_reg_list_info * reginfo,u32 addr,u32 flags)1653ecb63364SZhanjun Dong guc_capture_find_reg(struct gcap_reg_list_info *reginfo, u32 addr, u32 flags)
1654ecb63364SZhanjun Dong {
1655ecb63364SZhanjun Dong int i;
1656ecb63364SZhanjun Dong
1657ecb63364SZhanjun Dong if (reginfo && reginfo->num_regs > 0) {
1658ecb63364SZhanjun Dong struct guc_mmio_reg *regs = reginfo->regs;
1659ecb63364SZhanjun Dong
1660ecb63364SZhanjun Dong if (regs)
1661ecb63364SZhanjun Dong for (i = 0; i < reginfo->num_regs; i++)
1662ecb63364SZhanjun Dong if (regs[i].offset == addr && regs[i].flags == flags)
1663ecb63364SZhanjun Dong return ®s[i];
1664ecb63364SZhanjun Dong }
1665ecb63364SZhanjun Dong
1666ecb63364SZhanjun Dong return NULL;
1667ecb63364SZhanjun Dong }
1668ecb63364SZhanjun Dong
1669ecb63364SZhanjun Dong 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)1670ecb63364SZhanjun Dong snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p,
1671ecb63364SZhanjun Dong u32 type, const struct __guc_mmio_reg_descr_group *list)
1672ecb63364SZhanjun Dong {
1673ecb63364SZhanjun Dong struct xe_gt *gt = snapshot->hwe->gt;
1674ecb63364SZhanjun Dong struct xe_device *xe = gt_to_xe(gt);
1675ecb63364SZhanjun Dong struct xe_guc *guc = >->uc.guc;
1676ecb63364SZhanjun Dong struct xe_devcoredump *devcoredump = &xe->devcoredump;
1677ecb63364SZhanjun Dong struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot;
1678ecb63364SZhanjun Dong struct gcap_reg_list_info *reginfo = NULL;
1679*44958161SZhanjun Dong u32 i, last_value = 0;
1680*44958161SZhanjun Dong bool is_ext, low32_ready = false;
1681ecb63364SZhanjun Dong
1682*44958161SZhanjun Dong if (!list || !list->list || list->num_regs == 0)
1683ecb63364SZhanjun Dong return;
1684ecb63364SZhanjun Dong XE_WARN_ON(!devcore_snapshot->matched_node);
1685ecb63364SZhanjun Dong
1686ecb63364SZhanjun Dong is_ext = list == guc->capture->extlists;
1687ecb63364SZhanjun Dong reginfo = &devcore_snapshot->matched_node->reginfo[type];
1688ecb63364SZhanjun Dong
1689ecb63364SZhanjun Dong /*
1690ecb63364SZhanjun Dong * loop through descriptor first and find the register in the node
1691ecb63364SZhanjun Dong * this is more scalable for developer maintenance as it will ensure
1692ecb63364SZhanjun Dong * the printout matched the ordering of the static descriptor
1693ecb63364SZhanjun Dong * table-of-lists
1694ecb63364SZhanjun Dong */
1695ecb63364SZhanjun Dong for (i = 0; i < list->num_regs; i++) {
1696ecb63364SZhanjun Dong const struct __guc_mmio_reg_descr *reg_desc = &list->list[i];
1697ecb63364SZhanjun Dong struct guc_mmio_reg *reg;
1698ecb63364SZhanjun Dong u32 value;
1699ecb63364SZhanjun Dong
1700ecb63364SZhanjun Dong reg = guc_capture_find_reg(reginfo, reg_desc->reg.addr, reg_desc->flags);
1701ecb63364SZhanjun Dong if (!reg)
1702ecb63364SZhanjun Dong continue;
1703ecb63364SZhanjun Dong
1704ecb63364SZhanjun Dong value = reg->value;
1705*44958161SZhanjun Dong switch (reg_desc->data_type) {
1706*44958161SZhanjun Dong case REG_64BIT_LOW_DW:
1707ecb63364SZhanjun Dong last_value = value;
1708*44958161SZhanjun Dong
1709*44958161SZhanjun Dong /*
1710*44958161SZhanjun Dong * A 64 bit register define requires 2 consecutive
1711*44958161SZhanjun Dong * entries in register list, with low dword first
1712*44958161SZhanjun Dong * and hi dword the second, like:
1713*44958161SZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1714*44958161SZhanjun Dong * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, "XXX_REG"},
1715*44958161SZhanjun Dong *
1716*44958161SZhanjun Dong * Incorrect order will trigger XE_WARN.
1717*44958161SZhanjun Dong *
1718*44958161SZhanjun Dong * Possible double low here, for example:
1719*44958161SZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1720*44958161SZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1721*44958161SZhanjun Dong */
1722*44958161SZhanjun Dong XE_WARN_ON(low32_ready);
1723*44958161SZhanjun Dong low32_ready = true;
1724ecb63364SZhanjun Dong /* Low 32 bit dword saved, continue for high 32 bit */
1725*44958161SZhanjun Dong break;
1726*44958161SZhanjun Dong
1727*44958161SZhanjun Dong case REG_64BIT_HI_DW: {
1728ecb63364SZhanjun Dong u64 value_qw = ((u64)value << 32) | last_value;
1729ecb63364SZhanjun Dong
1730*44958161SZhanjun Dong /*
1731*44958161SZhanjun Dong * Incorrect 64bit register order. Possible missing low.
1732*44958161SZhanjun Dong * for example:
1733*44958161SZhanjun Dong * { XXX_REG(0), REG_32BIT, 0, 0, NULL},
1734*44958161SZhanjun Dong * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, NULL},
1735*44958161SZhanjun Dong */
1736*44958161SZhanjun Dong XE_WARN_ON(!low32_ready);
1737*44958161SZhanjun Dong low32_ready = false;
1738*44958161SZhanjun Dong
1739ecb63364SZhanjun Dong drm_printf(p, "\t%s: 0x%016llx\n", reg_desc->regname, value_qw);
1740*44958161SZhanjun Dong break;
1741ecb63364SZhanjun Dong }
1742ecb63364SZhanjun Dong
1743*44958161SZhanjun Dong case REG_32BIT:
1744*44958161SZhanjun Dong /*
1745*44958161SZhanjun Dong * Incorrect 64bit register order. Possible missing high.
1746*44958161SZhanjun Dong * for example:
1747*44958161SZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1748*44958161SZhanjun Dong * { XXX_REG(0), REG_32BIT, 0, 0, "XXX_REG"},
1749*44958161SZhanjun Dong */
1750*44958161SZhanjun Dong XE_WARN_ON(low32_ready);
1751*44958161SZhanjun Dong
1752ecb63364SZhanjun Dong if (is_ext) {
1753ecb63364SZhanjun Dong int dss, group, instance;
1754ecb63364SZhanjun Dong
1755ecb63364SZhanjun Dong group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags);
1756ecb63364SZhanjun Dong instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags);
1757ecb63364SZhanjun Dong dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance);
1758ecb63364SZhanjun Dong
1759ecb63364SZhanjun Dong drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value);
1760ecb63364SZhanjun Dong } else {
1761ecb63364SZhanjun Dong drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value);
1762ecb63364SZhanjun Dong }
1763*44958161SZhanjun Dong break;
1764ecb63364SZhanjun Dong }
1765ecb63364SZhanjun Dong }
1766ecb63364SZhanjun Dong
1767*44958161SZhanjun Dong /*
1768*44958161SZhanjun Dong * Incorrect 64bit register order. Possible missing high.
1769*44958161SZhanjun Dong * for example:
1770*44958161SZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL},
1771*44958161SZhanjun Dong * } // <- Register list end
1772*44958161SZhanjun Dong */
1773*44958161SZhanjun Dong XE_WARN_ON(low32_ready);
1774*44958161SZhanjun Dong }
1775*44958161SZhanjun Dong
1776ecb63364SZhanjun Dong /**
1777ecb63364SZhanjun Dong * xe_engine_snapshot_print - Print out a given Xe HW Engine snapshot.
1778ecb63364SZhanjun Dong * @snapshot: Xe HW Engine snapshot object.
1779ecb63364SZhanjun Dong * @p: drm_printer where it will be printed out.
1780ecb63364SZhanjun Dong *
1781ecb63364SZhanjun Dong * This function prints out a given Xe HW Engine snapshot object.
1782ecb63364SZhanjun Dong */
xe_engine_snapshot_print(struct xe_hw_engine_snapshot * snapshot,struct drm_printer * p)17830f1fdf55SZhanjun Dong void xe_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p)
1784ecb63364SZhanjun Dong {
1785ecb63364SZhanjun Dong const char *grptype[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = {
1786ecb63364SZhanjun Dong "full-capture",
1787ecb63364SZhanjun Dong "partial-capture"
1788ecb63364SZhanjun Dong };
1789ecb63364SZhanjun Dong int type;
1790ecb63364SZhanjun Dong const struct __guc_mmio_reg_descr_group *list;
1791ecb63364SZhanjun Dong enum guc_capture_list_class_type capture_class;
1792ecb63364SZhanjun Dong
1793ecb63364SZhanjun Dong struct xe_gt *gt;
1794ecb63364SZhanjun Dong struct xe_device *xe;
1795ecb63364SZhanjun Dong struct xe_devcoredump *devcoredump;
1796ecb63364SZhanjun Dong struct xe_devcoredump_snapshot *devcore_snapshot;
1797ecb63364SZhanjun Dong
1798ecb63364SZhanjun Dong if (!snapshot)
1799ecb63364SZhanjun Dong return;
1800ecb63364SZhanjun Dong
1801ecb63364SZhanjun Dong gt = snapshot->hwe->gt;
1802ecb63364SZhanjun Dong xe = gt_to_xe(gt);
1803ecb63364SZhanjun Dong devcoredump = &xe->devcoredump;
1804ecb63364SZhanjun Dong devcore_snapshot = &devcoredump->snapshot;
1805ecb63364SZhanjun Dong
1806ecb63364SZhanjun Dong if (!devcore_snapshot->matched_node)
1807ecb63364SZhanjun Dong return;
1808ecb63364SZhanjun Dong
1809ecb63364SZhanjun Dong xe_gt_assert(gt, snapshot->hwe);
1810ecb63364SZhanjun Dong
1811ecb63364SZhanjun Dong capture_class = xe_engine_class_to_guc_capture_class(snapshot->hwe->class);
1812ecb63364SZhanjun Dong
1813ecb63364SZhanjun Dong drm_printf(p, "%s (physical), logical instance=%d\n",
1814ecb63364SZhanjun Dong snapshot->name ? snapshot->name : "",
1815ecb63364SZhanjun Dong snapshot->logical_instance);
1816ecb63364SZhanjun Dong drm_printf(p, "\tCapture_source: %s\n",
1817ecb63364SZhanjun Dong devcore_snapshot->matched_node->source == XE_ENGINE_CAPTURE_SOURCE_GUC ?
1818ecb63364SZhanjun Dong "GuC" : "Manual");
1819ecb63364SZhanjun Dong drm_printf(p, "\tCoverage: %s\n", grptype[devcore_snapshot->matched_node->is_partial]);
1820ecb63364SZhanjun Dong drm_printf(p, "\tForcewake: domain 0x%x, ref %d\n",
1821ecb63364SZhanjun Dong snapshot->forcewake.domain, snapshot->forcewake.ref);
18220f1fdf55SZhanjun Dong drm_printf(p, "\tReserved: %s\n",
18230f1fdf55SZhanjun Dong str_yes_no(snapshot->kernel_reserved));
1824ecb63364SZhanjun Dong
1825ecb63364SZhanjun Dong for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) {
1826ecb63364SZhanjun Dong list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type,
1827ecb63364SZhanjun Dong capture_class, false);
1828ecb63364SZhanjun Dong snapshot_print_by_list_order(snapshot, p, type, list);
1829ecb63364SZhanjun Dong }
1830ecb63364SZhanjun Dong
1831ecb63364SZhanjun Dong if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) {
1832ecb63364SZhanjun Dong list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF,
1833ecb63364SZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
1834ecb63364SZhanjun Dong capture_class, true);
1835ecb63364SZhanjun Dong snapshot_print_by_list_order(snapshot, p, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
1836ecb63364SZhanjun Dong list);
1837ecb63364SZhanjun Dong }
1838ecb63364SZhanjun Dong
1839ecb63364SZhanjun Dong drm_puts(p, "\n");
1840ecb63364SZhanjun Dong }
1841ecb63364SZhanjun Dong
1842ecb63364SZhanjun Dong /**
1843ecb63364SZhanjun Dong * xe_guc_capture_get_matching_and_lock - Matching GuC capture for the queue.
1844ecb63364SZhanjun Dong * @q: The exec queue object
1845ecb63364SZhanjun Dong *
1846ecb63364SZhanjun Dong * Search within the capture outlist for the queue, could be used for check if
1847ecb63364SZhanjun Dong * GuC capture is ready for the queue.
1848ecb63364SZhanjun Dong * If found, the locked boolean of the node will be flagged.
1849ecb63364SZhanjun Dong *
1850ecb63364SZhanjun Dong * Returns: found guc-capture node ptr else NULL
1851ecb63364SZhanjun Dong */
1852ecb63364SZhanjun Dong struct __guc_capture_parsed_output *
xe_guc_capture_get_matching_and_lock(struct xe_exec_queue * q)1853ecb63364SZhanjun Dong xe_guc_capture_get_matching_and_lock(struct xe_exec_queue *q)
1854ecb63364SZhanjun Dong {
1855ecb63364SZhanjun Dong struct xe_hw_engine *hwe;
1856ecb63364SZhanjun Dong enum xe_hw_engine_id id;
1857ecb63364SZhanjun Dong struct xe_device *xe;
1858ecb63364SZhanjun Dong u16 guc_class = GUC_LAST_ENGINE_CLASS + 1;
1859ecb63364SZhanjun Dong struct xe_devcoredump_snapshot *ss;
1860ecb63364SZhanjun Dong
1861ecb63364SZhanjun Dong if (!q || !q->gt)
1862ecb63364SZhanjun Dong return NULL;
1863ecb63364SZhanjun Dong
1864ecb63364SZhanjun Dong xe = gt_to_xe(q->gt);
1865ecb63364SZhanjun Dong if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe) || IS_SRIOV_VF(xe))
1866ecb63364SZhanjun Dong return NULL;
1867ecb63364SZhanjun Dong
1868ecb63364SZhanjun Dong ss = &xe->devcoredump.snapshot;
1869ecb63364SZhanjun Dong if (ss->matched_node && ss->matched_node->source == XE_ENGINE_CAPTURE_SOURCE_GUC)
1870dd1ba621SZhanjun Dong return ss->matched_node;
1871ecb63364SZhanjun Dong
1872ecb63364SZhanjun Dong /* Find hwe for the queue */
1873ecb63364SZhanjun Dong for_each_hw_engine(hwe, q->gt, id) {
1874ecb63364SZhanjun Dong if (hwe != q->hwe)
1875ecb63364SZhanjun Dong continue;
1876ecb63364SZhanjun Dong guc_class = xe_engine_class_to_guc_class(hwe->class);
1877ecb63364SZhanjun Dong break;
1878ecb63364SZhanjun Dong }
1879ecb63364SZhanjun Dong
1880ecb63364SZhanjun Dong if (guc_class <= GUC_LAST_ENGINE_CLASS) {
1881ecb63364SZhanjun Dong struct __guc_capture_parsed_output *n, *ntmp;
1882ecb63364SZhanjun Dong struct xe_guc *guc = &q->gt->uc.guc;
1883ecb63364SZhanjun Dong u16 guc_id = q->guc->id;
1884ecb63364SZhanjun Dong u32 lrca = xe_lrc_ggtt_addr(q->lrc[0]);
1885ecb63364SZhanjun Dong
1886ecb63364SZhanjun Dong /*
1887ecb63364SZhanjun Dong * Look for a matching GuC reported error capture node from
1888ecb63364SZhanjun Dong * the internal output link-list based on engine, guc id and
1889ecb63364SZhanjun Dong * lrca info.
1890ecb63364SZhanjun Dong */
1891ecb63364SZhanjun Dong list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) {
1892ecb63364SZhanjun Dong if (n->eng_class == guc_class && n->eng_inst == hwe->instance &&
1893ecb63364SZhanjun Dong n->guc_id == guc_id && n->lrca == lrca &&
1894ecb63364SZhanjun Dong n->source == XE_ENGINE_CAPTURE_SOURCE_GUC) {
1895ecb63364SZhanjun Dong n->locked = 1;
1896ecb63364SZhanjun Dong return n;
1897ecb63364SZhanjun Dong }
1898ecb63364SZhanjun Dong }
1899ecb63364SZhanjun Dong }
1900ecb63364SZhanjun Dong return NULL;
1901ecb63364SZhanjun Dong }
1902ecb63364SZhanjun Dong
1903ecb63364SZhanjun Dong /**
1904ecb63364SZhanjun Dong * xe_engine_snapshot_capture_for_queue - Take snapshot of associated engine
1905ecb63364SZhanjun Dong * @q: The exec queue object
1906ecb63364SZhanjun Dong *
1907ecb63364SZhanjun Dong * Take snapshot of associated HW Engine
1908ecb63364SZhanjun Dong *
1909ecb63364SZhanjun Dong * Returns: None.
1910ecb63364SZhanjun Dong */
1911ecb63364SZhanjun Dong void
xe_engine_snapshot_capture_for_queue(struct xe_exec_queue * q)1912ecb63364SZhanjun Dong xe_engine_snapshot_capture_for_queue(struct xe_exec_queue *q)
1913ecb63364SZhanjun Dong {
1914ecb63364SZhanjun Dong struct xe_device *xe = gt_to_xe(q->gt);
1915ecb63364SZhanjun Dong struct xe_devcoredump *coredump = &xe->devcoredump;
1916ecb63364SZhanjun Dong struct xe_hw_engine *hwe;
1917ecb63364SZhanjun Dong enum xe_hw_engine_id id;
1918ecb63364SZhanjun Dong u32 adj_logical_mask = q->logical_mask;
1919ecb63364SZhanjun Dong
1920ecb63364SZhanjun Dong if (IS_SRIOV_VF(xe))
1921ecb63364SZhanjun Dong return;
1922ecb63364SZhanjun Dong
1923ecb63364SZhanjun Dong for_each_hw_engine(hwe, q->gt, id) {
1924ecb63364SZhanjun Dong if (hwe->class != q->hwe->class ||
1925ecb63364SZhanjun Dong !(BIT(hwe->logical_instance) & adj_logical_mask)) {
1926dd1ba621SZhanjun Dong coredump->snapshot.hwe[id] = NULL;
1927dd1ba621SZhanjun Dong continue;
1928dd1ba621SZhanjun Dong }
1929ecb63364SZhanjun Dong
1930ecb63364SZhanjun Dong if (!coredump->snapshot.hwe[id]) {
1931ecb63364SZhanjun Dong coredump->snapshot.hwe[id] =
1932ecb63364SZhanjun Dong xe_hw_engine_snapshot_capture(hwe, q);
1933ecb63364SZhanjun Dong } else {
1934ecb63364SZhanjun Dong struct __guc_capture_parsed_output *new;
1935ecb63364SZhanjun Dong
19360f1fdf55SZhanjun Dong new = xe_guc_capture_get_matching_and_lock(q);
1937ecb63364SZhanjun Dong if (new) {
19380f1fdf55SZhanjun Dong struct xe_guc *guc = &q->gt->uc.guc;
19390f1fdf55SZhanjun Dong
19400f1fdf55SZhanjun Dong /*
19410f1fdf55SZhanjun Dong * If we are in here, it means we found a fresh
19420f1fdf55SZhanjun Dong * GuC-err-capture node for this engine after
19430f1fdf55SZhanjun Dong * previously failing to find a match in the
19440f1fdf55SZhanjun Dong * early part of guc_exec_queue_timedout_job.
19450f1fdf55SZhanjun Dong * Thus we must free the manually captured node
19460f1fdf55SZhanjun Dong */
19470f1fdf55SZhanjun Dong guc_capture_free_outlist_node(guc->capture,
19480f1fdf55SZhanjun Dong coredump->snapshot.matched_node);
19490f1fdf55SZhanjun Dong coredump->snapshot.matched_node = new;
19500f1fdf55SZhanjun Dong }
19510f1fdf55SZhanjun Dong }
19520f1fdf55SZhanjun Dong
19530f1fdf55SZhanjun Dong break;
19540f1fdf55SZhanjun Dong }
19550f1fdf55SZhanjun Dong }
19560f1fdf55SZhanjun Dong
1957ecb63364SZhanjun Dong /*
1958ecb63364SZhanjun Dong * xe_guc_capture_put_matched_nodes - Cleanup matched nodes
1959ecb63364SZhanjun Dong * @guc: The GuC object
1960ecb63364SZhanjun Dong *
1961ecb63364SZhanjun Dong * Free matched node and all nodes with the equal guc_id from
1962ecb63364SZhanjun Dong * GuC captured outlist
1963ecb63364SZhanjun Dong */
xe_guc_capture_put_matched_nodes(struct xe_guc * guc)1964ecb63364SZhanjun Dong void xe_guc_capture_put_matched_nodes(struct xe_guc *guc)
1965ecb63364SZhanjun Dong {
1966ecb63364SZhanjun Dong struct xe_device *xe = guc_to_xe(guc);
1967ecb63364SZhanjun Dong struct xe_devcoredump *devcoredump = &xe->devcoredump;
1968ecb63364SZhanjun Dong struct __guc_capture_parsed_output *n = devcoredump->snapshot.matched_node;
1969ecb63364SZhanjun Dong
1970ecb63364SZhanjun Dong if (n) {
1971ecb63364SZhanjun Dong guc_capture_remove_stale_matches_from_list(guc->capture, n);
1972ecb63364SZhanjun Dong guc_capture_free_outlist_node(guc->capture, n);
1973ecb63364SZhanjun Dong devcoredump->snapshot.matched_node = NULL;
1974ecb63364SZhanjun Dong }
1975ecb63364SZhanjun Dong }
1976ecb63364SZhanjun Dong
1977ecb63364SZhanjun Dong /*
1978ecb63364SZhanjun Dong * xe_guc_capture_steered_list_init - Init steering register list
1979ecb63364SZhanjun Dong * @guc: The GuC object
1980ecb63364SZhanjun Dong *
1981ecb63364SZhanjun Dong * Init steering register list for GuC register capture, create pre-alloc node
1982b170d696SZhanjun Dong */
xe_guc_capture_steered_list_init(struct xe_guc * guc)1983b170d696SZhanjun Dong void xe_guc_capture_steered_list_init(struct xe_guc *guc)
1984b170d696SZhanjun Dong {
1985b170d696SZhanjun Dong /*
19868bfc4963SZhanjun Dong * For certain engine classes, there are slice and subslice
1987b170d696SZhanjun Dong * level registers requiring steering. We allocate and populate
1988b170d696SZhanjun Dong * these based on hw config and add it as an extension list at
1989b170d696SZhanjun Dong * the end of the pre-populated render list.
1990b170d696SZhanjun Dong */
1991b170d696SZhanjun Dong guc_capture_alloc_steered_lists(guc);
1992b170d696SZhanjun Dong check_guc_capture_size(guc);
1993b170d696SZhanjun Dong guc_capture_create_prealloc_nodes(guc);
1994b170d696SZhanjun Dong }
1995b170d696SZhanjun Dong
1996b170d696SZhanjun Dong /*
199784d15f42SZhanjun Dong * xe_guc_capture_init - Init for GuC register capture
19988bfc4963SZhanjun Dong * @guc: The GuC object
1999b170d696SZhanjun Dong *
2000b170d696SZhanjun Dong * Init for GuC register capture, alloc memory for capture data structure.
200184d15f42SZhanjun Dong *
20029c8c7a7eSZhanjun Dong * Returns: 0 if success.
20039c8c7a7eSZhanjun Dong * -ENOMEM if out of memory
20049c8c7a7eSZhanjun Dong */
xe_guc_capture_init(struct xe_guc * guc)20059c8c7a7eSZhanjun Dong int xe_guc_capture_init(struct xe_guc *guc)
20069c8c7a7eSZhanjun Dong {
20079c8c7a7eSZhanjun Dong guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL);
2008b170d696SZhanjun Dong if (!guc->capture)
20099c8c7a7eSZhanjun Dong return -ENOMEM;
20109c8c7a7eSZhanjun Dong
20119c8c7a7eSZhanjun Dong guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc));
20129c8c7a7eSZhanjun Dong
20139c8c7a7eSZhanjun Dong INIT_LIST_HEAD(&guc->capture->outlist);
20149c8c7a7eSZhanjun Dong INIT_LIST_HEAD(&guc->capture->cachelist);
20159c8c7a7eSZhanjun Dong
20169c8c7a7eSZhanjun Dong return 0;
20178bfc4963SZhanjun Dong }
20188bfc4963SZhanjun Dong