Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe: Add debugfs to dump GuC's hwconfig

Although the query uapi is the official way to get at the GuC's hwconfig
table contents, it's still useful to have a quick debugfs interface to
dump the table in a human-readable format while debugging the driver.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Reviewed-by: Jagmeet Randhawa <jagmeet.randhawa@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240815172602.2729146-3-matthew.d.roper@intel.com

+70
+11
drivers/gpu/drm/xe/xe_gt_debugfs.c
··· 19 19 #include "xe_gt_sriov_vf_debugfs.h" 20 20 #include "xe_gt_stats.h" 21 21 #include "xe_gt_topology.h" 22 + #include "xe_guc_hwconfig.h" 22 23 #include "xe_hw_engine.h" 23 24 #include "xe_lrc.h" 24 25 #include "xe_macros.h" ··· 271 270 return 0; 272 271 } 273 272 273 + static int hwconfig(struct xe_gt *gt, struct drm_printer *p) 274 + { 275 + xe_pm_runtime_get(gt_to_xe(gt)); 276 + xe_guc_hwconfig_dump(&gt->uc.guc, p); 277 + xe_pm_runtime_put(gt_to_xe(gt)); 278 + 279 + return 0; 280 + } 281 + 274 282 static const struct drm_info_list debugfs_list[] = { 275 283 {"hw_engines", .show = xe_gt_debugfs_simple_show, .data = hw_engines}, 276 284 {"force_reset", .show = xe_gt_debugfs_simple_show, .data = force_reset}, ··· 298 288 {"default_lrc_vcs", .show = xe_gt_debugfs_simple_show, .data = vcs_default_lrc}, 299 289 {"default_lrc_vecs", .show = xe_gt_debugfs_simple_show, .data = vecs_default_lrc}, 300 290 {"stats", .show = xe_gt_debugfs_simple_show, .data = xe_gt_stats_print_info}, 291 + {"hwconfig", .show = xe_gt_debugfs_simple_show, .data = hwconfig}, 301 292 }; 302 293 303 294 void xe_gt_debugfs_register(struct xe_gt *gt)
+57
drivers/gpu/drm/xe/xe_guc_hwconfig.c
··· 6 6 #include "xe_guc_hwconfig.h" 7 7 8 8 #include <drm/drm_managed.h> 9 + #include <drm/drm_print.h> 9 10 10 11 #include "abi/guc_actions_abi.h" 11 12 #include "xe_bo.h" ··· 103 102 104 103 xe_map_memcpy_from(xe, dst, &guc->hwconfig.bo->vmap, 0, 105 104 guc->hwconfig.size); 105 + } 106 + 107 + void xe_guc_hwconfig_dump(struct xe_guc *guc, struct drm_printer *p) 108 + { 109 + size_t size = xe_guc_hwconfig_size(guc); 110 + u32 *hwconfig; 111 + u64 num_dw; 112 + u32 extra_bytes; 113 + int i = 0; 114 + 115 + if (size == 0) { 116 + drm_printf(p, "No hwconfig available\n"); 117 + return; 118 + } 119 + 120 + num_dw = div_u64_rem(size, sizeof(u32), &extra_bytes); 121 + 122 + hwconfig = kzalloc(size, GFP_KERNEL); 123 + if (!hwconfig) { 124 + drm_printf(p, "Error: could not allocate hwconfig memory\n"); 125 + return; 126 + } 127 + 128 + xe_guc_hwconfig_copy(guc, hwconfig); 129 + 130 + /* An entry requires at least three dwords for key, length, value */ 131 + while (i + 3 <= num_dw) { 132 + u32 attribute = hwconfig[i++]; 133 + u32 len_dw = hwconfig[i++]; 134 + 135 + if (i + len_dw > num_dw) { 136 + drm_printf(p, "Error: Attribute %u is %u dwords, but only %llu remain\n", 137 + attribute, len_dw, num_dw - i); 138 + len_dw = num_dw - i; 139 + } 140 + 141 + /* 142 + * If it's a single dword (as most hwconfig attributes are), 143 + * then it's probably a number that makes sense to display 144 + * in decimal form. In the rare cases where it's more than 145 + * one dword, just print it in hex form and let the user 146 + * figure out how to interpret it. 147 + */ 148 + if (len_dw == 1) 149 + drm_printf(p, "[%2u] = %u\n", attribute, hwconfig[i]); 150 + else 151 + drm_printf(p, "[%2u] = { %*ph }\n", attribute, 152 + (int)(len_dw * sizeof(u32)), &hwconfig[i]); 153 + i += len_dw; 154 + } 155 + 156 + if (i < num_dw || extra_bytes) 157 + drm_printf(p, "Error: %llu extra bytes at end of hwconfig\n", 158 + (num_dw - i) * sizeof(u32) + extra_bytes); 159 + 160 + kfree(hwconfig); 106 161 }
+2
drivers/gpu/drm/xe/xe_guc_hwconfig.h
··· 8 8 9 9 #include <linux/types.h> 10 10 11 + struct drm_printer; 11 12 struct xe_guc; 12 13 13 14 int xe_guc_hwconfig_init(struct xe_guc *guc); 14 15 u32 xe_guc_hwconfig_size(struct xe_guc *guc); 15 16 void xe_guc_hwconfig_copy(struct xe_guc *guc, void *dst); 17 + void xe_guc_hwconfig_dump(struct xe_guc *guc, struct drm_printer *p); 16 18 17 19 #endif