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" 139c8c7a7eSZhanjun Dong #include "regs/xe_engine_regs.h" 149c8c7a7eSZhanjun Dong #include "regs/xe_gt_regs.h" 159c8c7a7eSZhanjun Dong #include "regs/xe_guc_regs.h" 169c8c7a7eSZhanjun Dong #include "regs/xe_regs.h" 179c8c7a7eSZhanjun Dong 189c8c7a7eSZhanjun Dong #include "xe_bo.h" 199c8c7a7eSZhanjun Dong #include "xe_device.h" 209c8c7a7eSZhanjun Dong #include "xe_exec_queue_types.h" 219c8c7a7eSZhanjun Dong #include "xe_gt.h" 229c8c7a7eSZhanjun Dong #include "xe_gt_mcr.h" 239c8c7a7eSZhanjun Dong #include "xe_gt_printk.h" 249c8c7a7eSZhanjun Dong #include "xe_guc.h" 25*84d15f42SZhanjun Dong #include "xe_guc_ads.h" 269c8c7a7eSZhanjun Dong #include "xe_guc_capture.h" 279c8c7a7eSZhanjun Dong #include "xe_guc_capture_types.h" 289c8c7a7eSZhanjun Dong #include "xe_guc_ct.h" 299c8c7a7eSZhanjun Dong #include "xe_guc_log.h" 309c8c7a7eSZhanjun Dong #include "xe_guc_submit.h" 319c8c7a7eSZhanjun Dong #include "xe_hw_engine_types.h" 329c8c7a7eSZhanjun Dong #include "xe_macros.h" 339c8c7a7eSZhanjun Dong #include "xe_map.h" 349c8c7a7eSZhanjun Dong 359c8c7a7eSZhanjun Dong /* 369c8c7a7eSZhanjun Dong * Define all device tables of GuC error capture register lists 379c8c7a7eSZhanjun Dong * NOTE: 389c8c7a7eSZhanjun Dong * For engine-registers, GuC only needs the register offsets 399c8c7a7eSZhanjun Dong * from the engine-mmio-base 409c8c7a7eSZhanjun Dong * 419c8c7a7eSZhanjun Dong * 64 bit registers need 2 entries for low 32 bit register and high 32 bit 429c8c7a7eSZhanjun Dong * register, for example: 439c8c7a7eSZhanjun Dong * Register data_type flags mask Register name 449c8c7a7eSZhanjun Dong * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 459c8c7a7eSZhanjun Dong * { XXX_REG_HI(0), REG_64BIT_HI_DW,, 0, 0, "XXX_REG"}, 469c8c7a7eSZhanjun Dong * 1. data_type: Indicate is hi/low 32 bit for a 64 bit register 479c8c7a7eSZhanjun Dong * A 64 bit register define requires 2 consecutive entries, 489c8c7a7eSZhanjun Dong * with low dword first and hi dword the second. 499c8c7a7eSZhanjun Dong * 2. Register name: null for incompleted define 509c8c7a7eSZhanjun Dong */ 519c8c7a7eSZhanjun Dong #define COMMON_XELP_BASE_GLOBAL \ 529c8c7a7eSZhanjun Dong { FORCEWAKE_GT, REG_32BIT, 0, 0, "FORCEWAKE_GT"} 539c8c7a7eSZhanjun Dong 549c8c7a7eSZhanjun Dong #define COMMON_BASE_ENGINE_INSTANCE \ 559c8c7a7eSZhanjun Dong { RING_HWSTAM(0), REG_32BIT, 0, 0, "HWSTAM"}, \ 569c8c7a7eSZhanjun Dong { RING_HWS_PGA(0), REG_32BIT, 0, 0, "RING_HWS_PGA"}, \ 579c8c7a7eSZhanjun Dong { RING_HEAD(0), REG_32BIT, 0, 0, "RING_HEAD"}, \ 589c8c7a7eSZhanjun Dong { RING_TAIL(0), REG_32BIT, 0, 0, "RING_TAIL"}, \ 599c8c7a7eSZhanjun Dong { RING_CTL(0), REG_32BIT, 0, 0, "RING_CTL"}, \ 609c8c7a7eSZhanjun Dong { RING_MI_MODE(0), REG_32BIT, 0, 0, "RING_MI_MODE"}, \ 619c8c7a7eSZhanjun Dong { RING_MODE(0), REG_32BIT, 0, 0, "RING_MODE"}, \ 629c8c7a7eSZhanjun Dong { RING_ESR(0), REG_32BIT, 0, 0, "RING_ESR"}, \ 639c8c7a7eSZhanjun Dong { RING_EMR(0), REG_32BIT, 0, 0, "RING_EMR"}, \ 649c8c7a7eSZhanjun Dong { RING_EIR(0), REG_32BIT, 0, 0, "RING_EIR"}, \ 659c8c7a7eSZhanjun Dong { RING_IMR(0), REG_32BIT, 0, 0, "RING_IMR"}, \ 669c8c7a7eSZhanjun Dong { RING_IPEHR(0), REG_32BIT, 0, 0, "IPEHR"}, \ 679c8c7a7eSZhanjun Dong { RING_INSTDONE(0), REG_32BIT, 0, 0, "RING_INSTDONE"}, \ 689c8c7a7eSZhanjun Dong { INDIRECT_RING_STATE(0), REG_32BIT, 0, 0, "INDIRECT_RING_STATE"}, \ 699c8c7a7eSZhanjun Dong { RING_ACTHD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 709c8c7a7eSZhanjun Dong { RING_ACTHD_UDW(0), REG_64BIT_HI_DW, 0, 0, "ACTHD"}, \ 719c8c7a7eSZhanjun Dong { RING_BBADDR(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 729c8c7a7eSZhanjun Dong { RING_BBADDR_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_BBADDR"}, \ 739c8c7a7eSZhanjun Dong { RING_START(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 749c8c7a7eSZhanjun Dong { RING_START_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_START"}, \ 759c8c7a7eSZhanjun Dong { RING_DMA_FADD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 769c8c7a7eSZhanjun Dong { RING_DMA_FADD_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_DMA_FADD"}, \ 779c8c7a7eSZhanjun Dong { RING_EXECLIST_STATUS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 789c8c7a7eSZhanjun Dong { RING_EXECLIST_STATUS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_STATUS"}, \ 799c8c7a7eSZhanjun Dong { RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \ 809c8c7a7eSZhanjun Dong { RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_SQ_CONTENTS"} 819c8c7a7eSZhanjun Dong 829c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS \ 839c8c7a7eSZhanjun Dong { RCU_MODE, REG_32BIT, 0, 0, "RCU_MODE"} 849c8c7a7eSZhanjun Dong 859c8c7a7eSZhanjun Dong #define COMMON_XELP_RC_CLASS_INSTDONE \ 869c8c7a7eSZhanjun Dong { SC_INSTDONE, REG_32BIT, 0, 0, "SC_INSTDONE"}, \ 879c8c7a7eSZhanjun Dong { SC_INSTDONE_EXTRA, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA"}, \ 889c8c7a7eSZhanjun Dong { SC_INSTDONE_EXTRA2, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA2"} 899c8c7a7eSZhanjun Dong 909c8c7a7eSZhanjun Dong #define XELP_VEC_CLASS_REGS \ 919c8c7a7eSZhanjun Dong { SFC_DONE(0), 0, 0, 0, "SFC_DONE[0]"}, \ 929c8c7a7eSZhanjun Dong { SFC_DONE(1), 0, 0, 0, "SFC_DONE[1]"}, \ 939c8c7a7eSZhanjun Dong { SFC_DONE(2), 0, 0, 0, "SFC_DONE[2]"}, \ 949c8c7a7eSZhanjun Dong { SFC_DONE(3), 0, 0, 0, "SFC_DONE[3]"} 959c8c7a7eSZhanjun Dong 969c8c7a7eSZhanjun Dong /* XE_LP Global */ 979c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = { 989c8c7a7eSZhanjun Dong COMMON_XELP_BASE_GLOBAL, 999c8c7a7eSZhanjun Dong }; 1009c8c7a7eSZhanjun Dong 1019c8c7a7eSZhanjun Dong /* Render / Compute Per-Engine-Instance */ 1029c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_inst_regs[] = { 1039c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE, 1049c8c7a7eSZhanjun Dong }; 1059c8c7a7eSZhanjun Dong 1069c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class */ 1079c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_rc_class_regs[] = { 1089c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS, 1099c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS_INSTDONE, 1109c8c7a7eSZhanjun Dong }; 1119c8c7a7eSZhanjun Dong 1129c8c7a7eSZhanjun Dong /* Render / Compute Engine-Class for xehpg */ 1139c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_hpg_rc_class_regs[] = { 1149c8c7a7eSZhanjun Dong COMMON_XELP_RC_CLASS, 1159c8c7a7eSZhanjun Dong }; 1169c8c7a7eSZhanjun Dong 1179c8c7a7eSZhanjun Dong /* Media Decode/Encode Per-Engine-Instance */ 1189c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vd_inst_regs[] = { 1199c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE, 1209c8c7a7eSZhanjun Dong }; 1219c8c7a7eSZhanjun Dong 1229c8c7a7eSZhanjun Dong /* Video Enhancement Engine-Class */ 1239c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_class_regs[] = { 1249c8c7a7eSZhanjun Dong XELP_VEC_CLASS_REGS, 1259c8c7a7eSZhanjun Dong }; 1269c8c7a7eSZhanjun Dong 1279c8c7a7eSZhanjun Dong /* Video Enhancement Per-Engine-Instance */ 1289c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_vec_inst_regs[] = { 1299c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE, 1309c8c7a7eSZhanjun Dong }; 1319c8c7a7eSZhanjun Dong 1329c8c7a7eSZhanjun Dong /* Blitter Per-Engine-Instance */ 1339c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_blt_inst_regs[] = { 1349c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE, 1359c8c7a7eSZhanjun Dong }; 1369c8c7a7eSZhanjun Dong 1379c8c7a7eSZhanjun Dong /* XE_LP - GSC Per-Engine-Instance */ 1389c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr xe_lp_gsc_inst_regs[] = { 1399c8c7a7eSZhanjun Dong COMMON_BASE_ENGINE_INSTANCE, 1409c8c7a7eSZhanjun Dong }; 1419c8c7a7eSZhanjun Dong 1429c8c7a7eSZhanjun Dong /* 1439c8c7a7eSZhanjun Dong * Empty list to prevent warnings about unknown class/instance types 1449c8c7a7eSZhanjun Dong * as not all class/instance types have entries on all platforms. 1459c8c7a7eSZhanjun Dong */ 1469c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr empty_regs_list[] = { 1479c8c7a7eSZhanjun Dong }; 1489c8c7a7eSZhanjun Dong 1499c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_OWNER(x) (GUC_CAPTURE_LIST_INDEX_##x) 1509c8c7a7eSZhanjun Dong #define TO_GCAP_DEF_TYPE(x) (GUC_STATE_CAPTURE_TYPE_##x) 1519c8c7a7eSZhanjun Dong #define MAKE_REGLIST(regslist, regsowner, regstype, class) \ 1529c8c7a7eSZhanjun Dong { \ 1539c8c7a7eSZhanjun Dong regslist, \ 1549c8c7a7eSZhanjun Dong ARRAY_SIZE(regslist), \ 1559c8c7a7eSZhanjun Dong TO_GCAP_DEF_OWNER(regsowner), \ 1569c8c7a7eSZhanjun Dong TO_GCAP_DEF_TYPE(regstype), \ 1579c8c7a7eSZhanjun Dong class \ 1589c8c7a7eSZhanjun Dong } 1599c8c7a7eSZhanjun Dong 1609c8c7a7eSZhanjun Dong /* List of lists for legacy graphic product version < 1255 */ 1619c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = { 1629c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0), 1639c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE), 1649c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE), 1659c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO), 1669c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO), 1679c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE), 1689c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE), 1699c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER), 1709c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER), 1719c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER), 1729c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER), 1739c8c7a7eSZhanjun Dong {} 1749c8c7a7eSZhanjun Dong }; 1759c8c7a7eSZhanjun Dong 1769c8c7a7eSZhanjun Dong /* List of lists for graphic product version >= 1255 */ 1779c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group xe_hpg_lists[] = { 1789c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_global_regs, PF, GLOBAL, 0), 1799c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_hpg_rc_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE), 1809c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE), 1819c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEO), 1829c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEO), 1839c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_class_regs, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE), 1849c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_vec_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE), 1859c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_BLITTER), 1869c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_blt_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_BLITTER), 1879c8c7a7eSZhanjun Dong MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_CAPTURE_LIST_CLASS_GSC_OTHER), 1889c8c7a7eSZhanjun Dong MAKE_REGLIST(xe_lp_gsc_inst_regs, PF, ENGINE_INSTANCE, GUC_CAPTURE_LIST_CLASS_GSC_OTHER), 1899c8c7a7eSZhanjun Dong {} 1909c8c7a7eSZhanjun Dong }; 1919c8c7a7eSZhanjun Dong 1929c8c7a7eSZhanjun Dong static const char * const capture_list_type_names[] = { 1939c8c7a7eSZhanjun Dong "Global", 1949c8c7a7eSZhanjun Dong "Class", 1959c8c7a7eSZhanjun Dong "Instance", 1969c8c7a7eSZhanjun Dong }; 1979c8c7a7eSZhanjun Dong 1989c8c7a7eSZhanjun Dong static const char * const capture_engine_class_names[] = { 1999c8c7a7eSZhanjun Dong "Render/Compute", 2009c8c7a7eSZhanjun Dong "Video", 2019c8c7a7eSZhanjun Dong "VideoEnhance", 2029c8c7a7eSZhanjun Dong "Blitter", 2039c8c7a7eSZhanjun Dong "GSC-Other", 2049c8c7a7eSZhanjun Dong }; 2059c8c7a7eSZhanjun Dong 2069c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache { 2079c8c7a7eSZhanjun Dong bool is_valid; 2089c8c7a7eSZhanjun Dong void *ptr; 2099c8c7a7eSZhanjun Dong size_t size; 2109c8c7a7eSZhanjun Dong int status; 2119c8c7a7eSZhanjun Dong }; 2129c8c7a7eSZhanjun Dong 2139c8c7a7eSZhanjun Dong struct xe_guc_state_capture { 2149c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *reglists; 215b170d696SZhanjun Dong /** 216b170d696SZhanjun Dong * NOTE: steered registers have multiple instances depending on the HW configuration 217b170d696SZhanjun Dong * (slices or dual-sub-slices) and thus depends on HW fuses discovered 218b170d696SZhanjun Dong */ 219b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists; 2209c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache ads_cache[GUC_CAPTURE_LIST_INDEX_MAX] 2219c8c7a7eSZhanjun Dong [GUC_STATE_CAPTURE_TYPE_MAX] 2229c8c7a7eSZhanjun Dong [GUC_CAPTURE_LIST_CLASS_MAX]; 2239c8c7a7eSZhanjun Dong void *ads_null_cache; 2249c8c7a7eSZhanjun Dong }; 2259c8c7a7eSZhanjun Dong 2269c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group * 2279c8c7a7eSZhanjun Dong guc_capture_get_device_reglist(struct xe_device *xe) 2289c8c7a7eSZhanjun Dong { 2299c8c7a7eSZhanjun Dong if (GRAPHICS_VERx100(xe) >= 1255) 2309c8c7a7eSZhanjun Dong return xe_hpg_lists; 2319c8c7a7eSZhanjun Dong else 2329c8c7a7eSZhanjun Dong return xe_lp_lists; 2339c8c7a7eSZhanjun Dong } 2349c8c7a7eSZhanjun Dong 2359c8c7a7eSZhanjun Dong static const struct __guc_mmio_reg_descr_group * 2369c8c7a7eSZhanjun Dong guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists, 2379c8c7a7eSZhanjun Dong u32 owner, u32 type, enum guc_capture_list_class_type capture_class) 2389c8c7a7eSZhanjun Dong { 2399c8c7a7eSZhanjun Dong int i; 2409c8c7a7eSZhanjun Dong 2419c8c7a7eSZhanjun Dong if (!reglists) 2429c8c7a7eSZhanjun Dong return NULL; 2439c8c7a7eSZhanjun Dong 2449c8c7a7eSZhanjun Dong for (i = 0; reglists[i].list; ++i) { 2459c8c7a7eSZhanjun Dong if (reglists[i].owner == owner && reglists[i].type == type && 2469c8c7a7eSZhanjun Dong (reglists[i].engine == capture_class || 2479c8c7a7eSZhanjun Dong reglists[i].type == GUC_STATE_CAPTURE_TYPE_GLOBAL)) 2489c8c7a7eSZhanjun Dong return ®lists[i]; 2499c8c7a7eSZhanjun Dong } 2509c8c7a7eSZhanjun Dong 2519c8c7a7eSZhanjun Dong return NULL; 2529c8c7a7eSZhanjun Dong } 2539c8c7a7eSZhanjun Dong 254b170d696SZhanjun Dong struct __ext_steer_reg { 255b170d696SZhanjun Dong const char *name; 256b170d696SZhanjun Dong struct xe_reg_mcr reg; 257b170d696SZhanjun Dong }; 258b170d696SZhanjun Dong 259b170d696SZhanjun Dong static const struct __ext_steer_reg xe_extregs[] = { 260b170d696SZhanjun Dong {"SAMPLER_INSTDONE", SAMPLER_INSTDONE}, 261b170d696SZhanjun Dong {"ROW_INSTDONE", ROW_INSTDONE} 262b170d696SZhanjun Dong }; 263b170d696SZhanjun Dong 264b170d696SZhanjun Dong static const struct __ext_steer_reg xehpg_extregs[] = { 265b170d696SZhanjun Dong {"SC_INSTDONE", XEHPG_SC_INSTDONE}, 266b170d696SZhanjun Dong {"SC_INSTDONE_EXTRA", XEHPG_SC_INSTDONE_EXTRA}, 267b170d696SZhanjun Dong {"SC_INSTDONE_EXTRA2", XEHPG_SC_INSTDONE_EXTRA2}, 268b170d696SZhanjun Dong {"INSTDONE_GEOM_SVGUNIT", XEHPG_INSTDONE_GEOM_SVGUNIT} 269b170d696SZhanjun Dong }; 270b170d696SZhanjun Dong 271b170d696SZhanjun Dong static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext, 272b170d696SZhanjun Dong const struct __ext_steer_reg *extlist, 273b170d696SZhanjun Dong int slice_id, int subslice_id) 274b170d696SZhanjun Dong { 275b170d696SZhanjun Dong if (!ext || !extlist) 276b170d696SZhanjun Dong return; 277b170d696SZhanjun Dong 278b170d696SZhanjun Dong ext->reg = XE_REG(extlist->reg.__reg.addr); 279b170d696SZhanjun Dong ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1); 280b170d696SZhanjun Dong ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id); 281b170d696SZhanjun Dong ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id); 282b170d696SZhanjun Dong ext->regname = extlist->name; 283b170d696SZhanjun Dong } 284b170d696SZhanjun Dong 285b170d696SZhanjun Dong static int 286b170d696SZhanjun Dong __alloc_ext_regs(struct drm_device *drm, struct __guc_mmio_reg_descr_group *newlist, 287b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *rootlist, int num_regs) 288b170d696SZhanjun Dong { 289b170d696SZhanjun Dong struct __guc_mmio_reg_descr *list; 290b170d696SZhanjun Dong 291b170d696SZhanjun Dong list = drmm_kzalloc(drm, num_regs * sizeof(struct __guc_mmio_reg_descr), GFP_KERNEL); 292b170d696SZhanjun Dong if (!list) 293b170d696SZhanjun Dong return -ENOMEM; 294b170d696SZhanjun Dong 295b170d696SZhanjun Dong newlist->list = list; 296b170d696SZhanjun Dong newlist->num_regs = num_regs; 297b170d696SZhanjun Dong newlist->owner = rootlist->owner; 298b170d696SZhanjun Dong newlist->engine = rootlist->engine; 299b170d696SZhanjun Dong newlist->type = rootlist->type; 300b170d696SZhanjun Dong 301b170d696SZhanjun Dong return 0; 302b170d696SZhanjun Dong } 303b170d696SZhanjun Dong 304b170d696SZhanjun Dong static int guc_capture_get_steer_reg_num(struct xe_device *xe) 305b170d696SZhanjun Dong { 306b170d696SZhanjun Dong int num = ARRAY_SIZE(xe_extregs); 307b170d696SZhanjun Dong 308b170d696SZhanjun Dong if (GRAPHICS_VERx100(xe) >= 1255) 309b170d696SZhanjun Dong num += ARRAY_SIZE(xehpg_extregs); 310b170d696SZhanjun Dong 311b170d696SZhanjun Dong return num; 312b170d696SZhanjun Dong } 313b170d696SZhanjun Dong 314b170d696SZhanjun Dong static void guc_capture_alloc_steered_lists(struct xe_guc *guc) 315b170d696SZhanjun Dong { 316b170d696SZhanjun Dong struct xe_gt *gt = guc_to_gt(guc); 317b170d696SZhanjun Dong u16 slice, subslice; 318b170d696SZhanjun Dong int iter, i, total = 0; 319b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists; 320b170d696SZhanjun Dong const struct __guc_mmio_reg_descr_group *list; 321b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists; 322b170d696SZhanjun Dong struct __guc_mmio_reg_descr *extarray; 323b170d696SZhanjun Dong bool has_xehpg_extregs = GRAPHICS_VERx100(gt_to_xe(gt)) >= 1255; 324b170d696SZhanjun Dong struct drm_device *drm = >_to_xe(gt)->drm; 325b170d696SZhanjun Dong bool has_rcs_ccs = false; 326b170d696SZhanjun Dong struct xe_hw_engine *hwe; 327b170d696SZhanjun Dong enum xe_hw_engine_id id; 328b170d696SZhanjun Dong 329b170d696SZhanjun Dong /* 330b170d696SZhanjun Dong * If GT has no rcs/ccs, no need to alloc steered list. 331b170d696SZhanjun Dong * Currently, only rcs/ccs has steering register, if in the future, 332b170d696SZhanjun Dong * other engine types has steering register, this condition check need 333b170d696SZhanjun Dong * to be extended 334b170d696SZhanjun Dong */ 335b170d696SZhanjun Dong for_each_hw_engine(hwe, gt, id) { 336b170d696SZhanjun Dong if (xe_engine_class_to_guc_capture_class(hwe->class) == 337b170d696SZhanjun Dong GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) { 338b170d696SZhanjun Dong has_rcs_ccs = true; 339b170d696SZhanjun Dong break; 340b170d696SZhanjun Dong } 341b170d696SZhanjun Dong } 342b170d696SZhanjun Dong 343b170d696SZhanjun Dong if (!has_rcs_ccs) 344b170d696SZhanjun Dong return; 345b170d696SZhanjun Dong 346b170d696SZhanjun Dong /* steered registers currently only exist for the render-class */ 347b170d696SZhanjun Dong list = guc_capture_get_one_list(lists, GUC_CAPTURE_LIST_INDEX_PF, 348b170d696SZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS, 349b170d696SZhanjun Dong GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE); 350b170d696SZhanjun Dong /* 351b170d696SZhanjun Dong * Skip if this platform has no engine class registers or if extlists 352b170d696SZhanjun Dong * was previously allocated 353b170d696SZhanjun Dong */ 354b170d696SZhanjun Dong if (!list || guc->capture->extlists) 355b170d696SZhanjun Dong return; 356b170d696SZhanjun Dong 357b170d696SZhanjun Dong total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) * 358b170d696SZhanjun Dong guc_capture_get_steer_reg_num(guc_to_xe(guc)); 359b170d696SZhanjun Dong 360b170d696SZhanjun Dong if (!total) 361b170d696SZhanjun Dong return; 362b170d696SZhanjun Dong 363b170d696SZhanjun Dong /* allocate an extra for an end marker */ 364b170d696SZhanjun Dong extlists = drmm_kzalloc(drm, 2 * sizeof(struct __guc_mmio_reg_descr_group), GFP_KERNEL); 365b170d696SZhanjun Dong if (!extlists) 366b170d696SZhanjun Dong return; 367b170d696SZhanjun Dong 368b170d696SZhanjun Dong if (__alloc_ext_regs(drm, &extlists[0], list, total)) { 369b170d696SZhanjun Dong drmm_kfree(drm, extlists); 370b170d696SZhanjun Dong return; 371b170d696SZhanjun Dong } 372b170d696SZhanjun Dong 373b170d696SZhanjun Dong /* For steering registers, the list is generated at run-time */ 374b170d696SZhanjun Dong extarray = (struct __guc_mmio_reg_descr *)extlists[0].list; 375b170d696SZhanjun Dong for_each_dss_steering(iter, gt, slice, subslice) { 376b170d696SZhanjun Dong for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) { 377b170d696SZhanjun Dong __fill_ext_reg(extarray, &xe_extregs[i], slice, subslice); 378b170d696SZhanjun Dong ++extarray; 379b170d696SZhanjun Dong } 380b170d696SZhanjun Dong 381b170d696SZhanjun Dong if (has_xehpg_extregs) 382b170d696SZhanjun Dong for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) { 383b170d696SZhanjun Dong __fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice); 384b170d696SZhanjun Dong ++extarray; 385b170d696SZhanjun Dong } 386b170d696SZhanjun Dong } 387b170d696SZhanjun Dong 388b170d696SZhanjun Dong extlists[0].num_regs = total; 389b170d696SZhanjun Dong 390b170d696SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "capture found %d ext-regs.\n", total); 391b170d696SZhanjun Dong guc->capture->extlists = extlists; 392b170d696SZhanjun Dong } 393b170d696SZhanjun Dong 3949c8c7a7eSZhanjun Dong static int 3959c8c7a7eSZhanjun Dong guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type, 3969c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, struct guc_mmio_reg *ptr, 3979c8c7a7eSZhanjun Dong u16 num_entries) 3989c8c7a7eSZhanjun Dong { 399b170d696SZhanjun Dong u32 ptr_idx = 0, list_idx = 0; 4009c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *reglists = guc->capture->reglists; 401b170d696SZhanjun Dong struct __guc_mmio_reg_descr_group *extlists = guc->capture->extlists; 4029c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *match; 403b170d696SZhanjun Dong u32 list_num; 4049c8c7a7eSZhanjun Dong 4059c8c7a7eSZhanjun Dong if (!reglists) 4069c8c7a7eSZhanjun Dong return -ENODEV; 4079c8c7a7eSZhanjun Dong 4089c8c7a7eSZhanjun Dong match = guc_capture_get_one_list(reglists, owner, type, capture_class); 4099c8c7a7eSZhanjun Dong if (!match) 4109c8c7a7eSZhanjun Dong return -ENODATA; 4119c8c7a7eSZhanjun Dong 412b170d696SZhanjun Dong list_num = match->num_regs; 413b170d696SZhanjun Dong for (list_idx = 0; ptr_idx < num_entries && list_idx < list_num; ++list_idx, ++ptr_idx) { 414b170d696SZhanjun Dong ptr[ptr_idx].offset = match->list[list_idx].reg.addr; 415b170d696SZhanjun Dong ptr[ptr_idx].value = 0xDEADF00D; 416b170d696SZhanjun Dong ptr[ptr_idx].flags = match->list[list_idx].flags; 417b170d696SZhanjun Dong ptr[ptr_idx].mask = match->list[list_idx].mask; 4189c8c7a7eSZhanjun Dong } 4199c8c7a7eSZhanjun Dong 420b170d696SZhanjun Dong match = guc_capture_get_one_list(extlists, owner, type, capture_class); 421b170d696SZhanjun Dong if (match) 422b170d696SZhanjun Dong for (ptr_idx = list_num, list_idx = 0; 423b170d696SZhanjun Dong ptr_idx < num_entries && list_idx < match->num_regs; 424b170d696SZhanjun Dong ++ptr_idx, ++list_idx) { 425b170d696SZhanjun Dong ptr[ptr_idx].offset = match->list[list_idx].reg.addr; 426b170d696SZhanjun Dong ptr[ptr_idx].value = 0xDEADF00D; 427b170d696SZhanjun Dong ptr[ptr_idx].flags = match->list[list_idx].flags; 428b170d696SZhanjun Dong ptr[ptr_idx].mask = match->list[list_idx].mask; 429b170d696SZhanjun Dong } 430b170d696SZhanjun Dong 431b170d696SZhanjun Dong if (ptr_idx < num_entries) 432b170d696SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "Got short capture reglist init: %d out-of %d.\n", 433b170d696SZhanjun Dong ptr_idx, num_entries); 4349c8c7a7eSZhanjun Dong 4359c8c7a7eSZhanjun Dong return 0; 4369c8c7a7eSZhanjun Dong } 4379c8c7a7eSZhanjun Dong 4389c8c7a7eSZhanjun Dong static int 4399c8c7a7eSZhanjun Dong guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type, 4409c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class) 4419c8c7a7eSZhanjun Dong { 4429c8c7a7eSZhanjun Dong const struct __guc_mmio_reg_descr_group *match; 443b170d696SZhanjun Dong int num_regs = 0; 4449c8c7a7eSZhanjun Dong 4459c8c7a7eSZhanjun Dong match = guc_capture_get_one_list(guc->capture->reglists, owner, type, capture_class); 446b170d696SZhanjun Dong if (match) 447b170d696SZhanjun Dong num_regs = match->num_regs; 4489c8c7a7eSZhanjun Dong 449b170d696SZhanjun Dong match = guc_capture_get_one_list(guc->capture->extlists, owner, type, capture_class); 450b170d696SZhanjun Dong if (match) 451b170d696SZhanjun Dong num_regs += match->num_regs; 452b170d696SZhanjun Dong else 453b170d696SZhanjun Dong /* Estimate steering register size for rcs/ccs */ 454b170d696SZhanjun Dong if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) 455b170d696SZhanjun Dong num_regs += guc_capture_get_steer_reg_num(guc_to_xe(guc)) * 456b170d696SZhanjun Dong XE_MAX_DSS_FUSE_BITS; 457b170d696SZhanjun Dong 458b170d696SZhanjun Dong return num_regs; 4599c8c7a7eSZhanjun Dong } 4609c8c7a7eSZhanjun Dong 4619c8c7a7eSZhanjun Dong static int 4629c8c7a7eSZhanjun Dong guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type, 4639c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, 4649c8c7a7eSZhanjun Dong size_t *size, bool is_purpose_est) 4659c8c7a7eSZhanjun Dong { 4669c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture; 4679c8c7a7eSZhanjun Dong struct xe_gt *gt = guc_to_gt(guc); 4689c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache *cache; 4699c8c7a7eSZhanjun Dong int num_regs; 4709c8c7a7eSZhanjun Dong 4719c8c7a7eSZhanjun Dong xe_gt_assert(gt, type < GUC_STATE_CAPTURE_TYPE_MAX); 4729c8c7a7eSZhanjun Dong xe_gt_assert(gt, capture_class < GUC_CAPTURE_LIST_CLASS_MAX); 4739c8c7a7eSZhanjun Dong 4749c8c7a7eSZhanjun Dong cache = &gc->ads_cache[owner][type][capture_class]; 4759c8c7a7eSZhanjun Dong if (!gc->reglists) { 4769c8c7a7eSZhanjun Dong xe_gt_warn(gt, "No capture reglist for this device\n"); 4779c8c7a7eSZhanjun Dong return -ENODEV; 4789c8c7a7eSZhanjun Dong } 4799c8c7a7eSZhanjun Dong 4809c8c7a7eSZhanjun Dong if (cache->is_valid) { 4819c8c7a7eSZhanjun Dong *size = cache->size; 4829c8c7a7eSZhanjun Dong return cache->status; 4839c8c7a7eSZhanjun Dong } 4849c8c7a7eSZhanjun Dong 4859c8c7a7eSZhanjun Dong if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF && 4869c8c7a7eSZhanjun Dong !guc_capture_get_one_list(gc->reglists, owner, type, capture_class)) { 4879c8c7a7eSZhanjun Dong if (type == GUC_STATE_CAPTURE_TYPE_GLOBAL) 4889c8c7a7eSZhanjun Dong xe_gt_warn(gt, "Missing capture reglist: global!\n"); 4899c8c7a7eSZhanjun Dong else 4909c8c7a7eSZhanjun Dong xe_gt_warn(gt, "Missing capture reglist: %s(%u):%s(%u)!\n", 4919c8c7a7eSZhanjun Dong capture_list_type_names[type], type, 4929c8c7a7eSZhanjun Dong capture_engine_class_names[capture_class], capture_class); 4939c8c7a7eSZhanjun Dong return -ENODEV; 4949c8c7a7eSZhanjun Dong } 4959c8c7a7eSZhanjun Dong 4969c8c7a7eSZhanjun Dong num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class); 4979c8c7a7eSZhanjun Dong /* intentional empty lists can exist depending on hw config */ 4989c8c7a7eSZhanjun Dong if (!num_regs) 4999c8c7a7eSZhanjun Dong return -ENODATA; 5009c8c7a7eSZhanjun Dong 5019c8c7a7eSZhanjun Dong if (size) 5029c8c7a7eSZhanjun Dong *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) + 5039c8c7a7eSZhanjun Dong (num_regs * sizeof(struct guc_mmio_reg))); 5049c8c7a7eSZhanjun Dong 5059c8c7a7eSZhanjun Dong return 0; 5069c8c7a7eSZhanjun Dong } 5079c8c7a7eSZhanjun Dong 5089c8c7a7eSZhanjun Dong /** 5099c8c7a7eSZhanjun Dong * xe_guc_capture_getlistsize - Get list size for owner/type/class combination 5109c8c7a7eSZhanjun Dong * @guc: The GuC object 5119c8c7a7eSZhanjun Dong * @owner: PF/VF owner 5129c8c7a7eSZhanjun Dong * @type: GuC capture register type 5139c8c7a7eSZhanjun Dong * @capture_class: GuC capture engine class id 5149c8c7a7eSZhanjun Dong * @size: Point to the size 5159c8c7a7eSZhanjun Dong * 5169c8c7a7eSZhanjun Dong * This function will get the list for the owner/type/class combination, and 5179c8c7a7eSZhanjun Dong * return the page aligned list size. 5189c8c7a7eSZhanjun Dong * 5199c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure. 5209c8c7a7eSZhanjun Dong */ 5219c8c7a7eSZhanjun Dong int 5229c8c7a7eSZhanjun Dong xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type, 5239c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, size_t *size) 5249c8c7a7eSZhanjun Dong { 5259c8c7a7eSZhanjun Dong return guc_capture_getlistsize(guc, owner, type, capture_class, size, false); 5269c8c7a7eSZhanjun Dong } 5279c8c7a7eSZhanjun Dong 5289c8c7a7eSZhanjun Dong /** 5299c8c7a7eSZhanjun Dong * xe_guc_capture_getlist - Get register capture list for owner/type/class 5309c8c7a7eSZhanjun Dong * combination 5319c8c7a7eSZhanjun Dong * @guc: The GuC object 5329c8c7a7eSZhanjun Dong * @owner: PF/VF owner 5339c8c7a7eSZhanjun Dong * @type: GuC capture register type 5349c8c7a7eSZhanjun Dong * @capture_class: GuC capture engine class id 5359c8c7a7eSZhanjun Dong * @outptr: Point to cached register capture list 5369c8c7a7eSZhanjun Dong * 5379c8c7a7eSZhanjun Dong * This function will get the register capture list for the owner/type/class 5389c8c7a7eSZhanjun Dong * combination. 5399c8c7a7eSZhanjun Dong * 5409c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure. 5419c8c7a7eSZhanjun Dong */ 5429c8c7a7eSZhanjun Dong int 5439c8c7a7eSZhanjun Dong xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type, 5449c8c7a7eSZhanjun Dong enum guc_capture_list_class_type capture_class, void **outptr) 5459c8c7a7eSZhanjun Dong { 5469c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture; 5479c8c7a7eSZhanjun Dong struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][capture_class]; 5489c8c7a7eSZhanjun Dong struct guc_debug_capture_list *listnode; 5499c8c7a7eSZhanjun Dong int ret, num_regs; 5509c8c7a7eSZhanjun Dong u8 *caplist, *tmp; 5519c8c7a7eSZhanjun Dong size_t size = 0; 5529c8c7a7eSZhanjun Dong 5539c8c7a7eSZhanjun Dong if (!gc->reglists) 5549c8c7a7eSZhanjun Dong return -ENODEV; 5559c8c7a7eSZhanjun Dong 5569c8c7a7eSZhanjun Dong if (cache->is_valid) { 5579c8c7a7eSZhanjun Dong *outptr = cache->ptr; 5589c8c7a7eSZhanjun Dong return cache->status; 5599c8c7a7eSZhanjun Dong } 5609c8c7a7eSZhanjun Dong 5619c8c7a7eSZhanjun Dong ret = xe_guc_capture_getlistsize(guc, owner, type, capture_class, &size); 5629c8c7a7eSZhanjun Dong if (ret) { 5639c8c7a7eSZhanjun Dong cache->is_valid = true; 5649c8c7a7eSZhanjun Dong cache->ptr = NULL; 5659c8c7a7eSZhanjun Dong cache->size = 0; 5669c8c7a7eSZhanjun Dong cache->status = ret; 5679c8c7a7eSZhanjun Dong return ret; 5689c8c7a7eSZhanjun Dong } 5699c8c7a7eSZhanjun Dong 5709c8c7a7eSZhanjun Dong caplist = drmm_kzalloc(guc_to_drm(guc), size, GFP_KERNEL); 5719c8c7a7eSZhanjun Dong if (!caplist) 5729c8c7a7eSZhanjun Dong return -ENOMEM; 5739c8c7a7eSZhanjun Dong 5749c8c7a7eSZhanjun Dong /* populate capture list header */ 5759c8c7a7eSZhanjun Dong tmp = caplist; 5769c8c7a7eSZhanjun Dong num_regs = guc_cap_list_num_regs(guc, owner, type, capture_class); 5779c8c7a7eSZhanjun Dong listnode = (struct guc_debug_capture_list *)tmp; 5789c8c7a7eSZhanjun Dong listnode->header.info = FIELD_PREP(GUC_CAPTURELISTHDR_NUMDESCR, (u32)num_regs); 5799c8c7a7eSZhanjun Dong 5809c8c7a7eSZhanjun Dong /* populate list of register descriptor */ 5819c8c7a7eSZhanjun Dong tmp += sizeof(struct guc_debug_capture_list); 5829c8c7a7eSZhanjun Dong guc_capture_list_init(guc, owner, type, capture_class, 5839c8c7a7eSZhanjun Dong (struct guc_mmio_reg *)tmp, num_regs); 5849c8c7a7eSZhanjun Dong 5859c8c7a7eSZhanjun Dong /* cache this list */ 5869c8c7a7eSZhanjun Dong cache->is_valid = true; 5879c8c7a7eSZhanjun Dong cache->ptr = caplist; 5889c8c7a7eSZhanjun Dong cache->size = size; 5899c8c7a7eSZhanjun Dong cache->status = 0; 5909c8c7a7eSZhanjun Dong 5919c8c7a7eSZhanjun Dong *outptr = caplist; 5929c8c7a7eSZhanjun Dong 5939c8c7a7eSZhanjun Dong return 0; 5949c8c7a7eSZhanjun Dong } 5959c8c7a7eSZhanjun Dong 5969c8c7a7eSZhanjun Dong /** 5979c8c7a7eSZhanjun Dong * xe_guc_capture_getnullheader - Get a null list for register capture 5989c8c7a7eSZhanjun Dong * @guc: The GuC object 5999c8c7a7eSZhanjun Dong * @outptr: Point to cached register capture list 6009c8c7a7eSZhanjun Dong * @size: Point to the size 6019c8c7a7eSZhanjun Dong * 6029c8c7a7eSZhanjun Dong * This function will alloc for a null list for register capture. 6039c8c7a7eSZhanjun Dong * 6049c8c7a7eSZhanjun Dong * Returns: 0 on success or a negative error code on failure. 6059c8c7a7eSZhanjun Dong */ 6069c8c7a7eSZhanjun Dong int 6079c8c7a7eSZhanjun Dong xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size) 6089c8c7a7eSZhanjun Dong { 6099c8c7a7eSZhanjun Dong struct xe_guc_state_capture *gc = guc->capture; 6109c8c7a7eSZhanjun Dong int tmp = sizeof(u32) * 4; 6119c8c7a7eSZhanjun Dong void *null_header; 6129c8c7a7eSZhanjun Dong 6139c8c7a7eSZhanjun Dong if (gc->ads_null_cache) { 6149c8c7a7eSZhanjun Dong *outptr = gc->ads_null_cache; 6159c8c7a7eSZhanjun Dong *size = tmp; 6169c8c7a7eSZhanjun Dong return 0; 6179c8c7a7eSZhanjun Dong } 6189c8c7a7eSZhanjun Dong 6199c8c7a7eSZhanjun Dong null_header = drmm_kzalloc(guc_to_drm(guc), tmp, GFP_KERNEL); 6209c8c7a7eSZhanjun Dong if (!null_header) 6219c8c7a7eSZhanjun Dong return -ENOMEM; 6229c8c7a7eSZhanjun Dong 6239c8c7a7eSZhanjun Dong gc->ads_null_cache = null_header; 6249c8c7a7eSZhanjun Dong *outptr = null_header; 6259c8c7a7eSZhanjun Dong *size = tmp; 6269c8c7a7eSZhanjun Dong 6279c8c7a7eSZhanjun Dong return 0; 6289c8c7a7eSZhanjun Dong } 6299c8c7a7eSZhanjun Dong 6309c8c7a7eSZhanjun Dong /** 6319c8c7a7eSZhanjun Dong * xe_guc_capture_ads_input_worst_size - Calculate the worst size for GuC register capture 6329c8c7a7eSZhanjun Dong * @guc: point to xe_guc structure 6339c8c7a7eSZhanjun Dong * 6349c8c7a7eSZhanjun Dong * Calculate the worst size for GuC register capture by including all possible engines classes. 6359c8c7a7eSZhanjun Dong * 6369c8c7a7eSZhanjun Dong * Returns: Calculated size 6379c8c7a7eSZhanjun Dong */ 6389c8c7a7eSZhanjun Dong size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc) 6399c8c7a7eSZhanjun Dong { 6409c8c7a7eSZhanjun Dong size_t total_size, class_size, instance_size, global_size; 6419c8c7a7eSZhanjun Dong int i, j; 6429c8c7a7eSZhanjun Dong 6439c8c7a7eSZhanjun Dong /* 6449c8c7a7eSZhanjun Dong * This function calculates the worst case register lists size by 6459c8c7a7eSZhanjun Dong * including all possible engines classes. It is called during the 6469c8c7a7eSZhanjun Dong * first of a two-phase GuC (and ADS-population) initialization 6479c8c7a7eSZhanjun Dong * sequence, that is, during the pre-hwconfig phase before we have 6489c8c7a7eSZhanjun Dong * the exact engine fusing info. 6499c8c7a7eSZhanjun Dong */ 6509c8c7a7eSZhanjun Dong total_size = PAGE_SIZE; /* Pad a page in front for empty lists */ 6519c8c7a7eSZhanjun Dong for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) { 6529c8c7a7eSZhanjun Dong for (j = 0; j < GUC_CAPTURE_LIST_CLASS_MAX; j++) { 6539c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i, 6549c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS, 6559c8c7a7eSZhanjun Dong j, &class_size) < 0) 6569c8c7a7eSZhanjun Dong class_size = 0; 6579c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i, 6589c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE, 6599c8c7a7eSZhanjun Dong j, &instance_size) < 0) 6609c8c7a7eSZhanjun Dong instance_size = 0; 6619c8c7a7eSZhanjun Dong total_size += class_size + instance_size; 6629c8c7a7eSZhanjun Dong } 6639c8c7a7eSZhanjun Dong if (xe_guc_capture_getlistsize(guc, i, 6649c8c7a7eSZhanjun Dong GUC_STATE_CAPTURE_TYPE_GLOBAL, 6659c8c7a7eSZhanjun Dong 0, &global_size) < 0) 6669c8c7a7eSZhanjun Dong global_size = 0; 6679c8c7a7eSZhanjun Dong total_size += global_size; 6689c8c7a7eSZhanjun Dong } 6699c8c7a7eSZhanjun Dong 6709c8c7a7eSZhanjun Dong return PAGE_ALIGN(total_size); 6719c8c7a7eSZhanjun Dong } 6729c8c7a7eSZhanjun Dong 673*84d15f42SZhanjun Dong static int guc_capture_output_size_est(struct xe_guc *guc) 674*84d15f42SZhanjun Dong { 675*84d15f42SZhanjun Dong struct xe_gt *gt = guc_to_gt(guc); 676*84d15f42SZhanjun Dong struct xe_hw_engine *hwe; 677*84d15f42SZhanjun Dong enum xe_hw_engine_id id; 678*84d15f42SZhanjun Dong 679*84d15f42SZhanjun Dong int capture_size = 0; 680*84d15f42SZhanjun Dong size_t tmp = 0; 681*84d15f42SZhanjun Dong 682*84d15f42SZhanjun Dong if (!guc->capture) 683*84d15f42SZhanjun Dong return -ENODEV; 684*84d15f42SZhanjun Dong 685*84d15f42SZhanjun Dong /* 686*84d15f42SZhanjun Dong * If every single engine-instance suffered a failure in quick succession but 687*84d15f42SZhanjun Dong * were all unrelated, then a burst of multiple error-capture events would dump 688*84d15f42SZhanjun Dong * registers for every one engine instance, one at a time. In this case, GuC 689*84d15f42SZhanjun Dong * would even dump the global-registers repeatedly. 690*84d15f42SZhanjun Dong * 691*84d15f42SZhanjun Dong * For each engine instance, there would be 1 x guc_state_capture_group_t output 692*84d15f42SZhanjun Dong * followed by 3 x guc_state_capture_t lists. The latter is how the register 693*84d15f42SZhanjun Dong * dumps are split across different register types (where the '3' are global vs class 694*84d15f42SZhanjun Dong * vs instance). 695*84d15f42SZhanjun Dong */ 696*84d15f42SZhanjun Dong for_each_hw_engine(hwe, gt, id) { 697*84d15f42SZhanjun Dong enum guc_capture_list_class_type capture_class; 698*84d15f42SZhanjun Dong 699*84d15f42SZhanjun Dong capture_class = xe_engine_class_to_guc_capture_class(hwe->class); 700*84d15f42SZhanjun Dong capture_size += sizeof(struct guc_state_capture_group_header_t) + 701*84d15f42SZhanjun Dong (3 * sizeof(struct guc_state_capture_header_t)); 702*84d15f42SZhanjun Dong 703*84d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_GLOBAL, 704*84d15f42SZhanjun Dong 0, &tmp, true)) 705*84d15f42SZhanjun Dong capture_size += tmp; 706*84d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS, 707*84d15f42SZhanjun Dong capture_class, &tmp, true)) 708*84d15f42SZhanjun Dong capture_size += tmp; 709*84d15f42SZhanjun Dong if (!guc_capture_getlistsize(guc, 0, GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE, 710*84d15f42SZhanjun Dong capture_class, &tmp, true)) 711*84d15f42SZhanjun Dong capture_size += tmp; 712*84d15f42SZhanjun Dong } 713*84d15f42SZhanjun Dong 714*84d15f42SZhanjun Dong return capture_size; 715*84d15f42SZhanjun Dong } 716*84d15f42SZhanjun Dong 717*84d15f42SZhanjun Dong /* 718*84d15f42SZhanjun Dong * Add on a 3x multiplier to allow for multiple back-to-back captures occurring 719*84d15f42SZhanjun Dong * before the Xe can read the data out and process it 720*84d15f42SZhanjun Dong */ 721*84d15f42SZhanjun Dong #define GUC_CAPTURE_OVERBUFFER_MULTIPLIER 3 722*84d15f42SZhanjun Dong 723*84d15f42SZhanjun Dong static void check_guc_capture_size(struct xe_guc *guc) 724*84d15f42SZhanjun Dong { 725*84d15f42SZhanjun Dong int capture_size = guc_capture_output_size_est(guc); 726*84d15f42SZhanjun Dong int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER; 727*84d15f42SZhanjun Dong u32 buffer_size = xe_guc_log_section_size_capture(&guc->log); 728*84d15f42SZhanjun Dong 729*84d15f42SZhanjun Dong /* 730*84d15f42SZhanjun Dong * NOTE: capture_size is much smaller than the capture region 731*84d15f42SZhanjun Dong * allocation (DG2: <80K vs 1MB). 732*84d15f42SZhanjun Dong * Additionally, its based on space needed to fit all engines getting 733*84d15f42SZhanjun Dong * reset at once within the same G2H handler task slot. This is very 734*84d15f42SZhanjun Dong * unlikely. However, if GuC really does run out of space for whatever 735*84d15f42SZhanjun Dong * reason, we will see an separate warning message when processing the 736*84d15f42SZhanjun Dong * G2H event capture-notification, search for: 737*84d15f42SZhanjun Dong * xe_guc_STATE_CAPTURE_EVENT_STATUS_NOSPACE. 738*84d15f42SZhanjun Dong */ 739*84d15f42SZhanjun Dong if (capture_size < 0) 740*84d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), 741*84d15f42SZhanjun Dong "Failed to calculate error state capture buffer minimum size: %d!\n", 742*84d15f42SZhanjun Dong capture_size); 743*84d15f42SZhanjun Dong if (capture_size > buffer_size) 744*84d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), "Error state capture buffer maybe small: %d < %d\n", 745*84d15f42SZhanjun Dong buffer_size, capture_size); 746*84d15f42SZhanjun Dong else if (spare_size > buffer_size) 747*84d15f42SZhanjun Dong xe_gt_dbg(guc_to_gt(guc), 748*84d15f42SZhanjun Dong "Error state capture buffer lacks spare size: %d < %d (min = %d)\n", 749*84d15f42SZhanjun Dong buffer_size, spare_size, capture_size); 750*84d15f42SZhanjun Dong } 751*84d15f42SZhanjun Dong 752b170d696SZhanjun Dong /* 753b170d696SZhanjun Dong * xe_guc_capture_steered_list_init - Init steering register list 754b170d696SZhanjun Dong * @guc: The GuC object 755b170d696SZhanjun Dong * 756b170d696SZhanjun Dong * Init steering register list for GuC register capture 757b170d696SZhanjun Dong */ 758b170d696SZhanjun Dong void xe_guc_capture_steered_list_init(struct xe_guc *guc) 759b170d696SZhanjun Dong { 760b170d696SZhanjun Dong /* 761b170d696SZhanjun Dong * For certain engine classes, there are slice and subslice 762b170d696SZhanjun Dong * level registers requiring steering. We allocate and populate 763b170d696SZhanjun Dong * these based on hw config and add it as an extension list at 764b170d696SZhanjun Dong * the end of the pre-populated render list. 765b170d696SZhanjun Dong */ 766b170d696SZhanjun Dong guc_capture_alloc_steered_lists(guc); 767*84d15f42SZhanjun Dong check_guc_capture_size(guc); 768b170d696SZhanjun Dong } 769b170d696SZhanjun Dong 770*84d15f42SZhanjun Dong /* 7719c8c7a7eSZhanjun Dong * xe_guc_capture_init - Init for GuC register capture 7729c8c7a7eSZhanjun Dong * @guc: The GuC object 7739c8c7a7eSZhanjun Dong * 7749c8c7a7eSZhanjun Dong * Init for GuC register capture, alloc memory for capture data structure. 7759c8c7a7eSZhanjun Dong * 7769c8c7a7eSZhanjun Dong * Returns: 0 if success. 777b170d696SZhanjun Dong * -ENOMEM if out of memory 7789c8c7a7eSZhanjun Dong */ 7799c8c7a7eSZhanjun Dong int xe_guc_capture_init(struct xe_guc *guc) 7809c8c7a7eSZhanjun Dong { 7819c8c7a7eSZhanjun Dong guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL); 7829c8c7a7eSZhanjun Dong if (!guc->capture) 7839c8c7a7eSZhanjun Dong return -ENOMEM; 7849c8c7a7eSZhanjun Dong 7859c8c7a7eSZhanjun Dong guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc)); 7869c8c7a7eSZhanjun Dong return 0; 7879c8c7a7eSZhanjun Dong } 788