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