| 1 | // SPDX-License-Identifier: MIT |
| 2 | /* |
| 3 | * Copyright © 2022 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include "xe_guc_debugfs.h" |
| 7 | |
| 8 | #include <drm/drm_debugfs.h> |
| 9 | #include <drm/drm_managed.h> |
| 10 | |
| 11 | #include "xe_device.h" |
| 12 | #include "xe_gt.h" |
| 13 | #include "xe_guc.h" |
| 14 | #include "xe_guc_ct.h" |
| 15 | #include "xe_guc_log.h" |
| 16 | #include "xe_guc_pc.h" |
| 17 | #include "xe_macros.h" |
| 18 | #include "xe_pm.h" |
| 19 | |
| 20 | /* |
| 21 | * guc_debugfs_show - A show callback for struct drm_info_list |
| 22 | * @m: the &seq_file |
| 23 | * @data: data used by the drm debugfs helpers |
| 24 | * |
| 25 | * This callback can be used in struct drm_info_list to describe debugfs |
| 26 | * files that are &xe_guc specific in similar way how we handle &xe_gt |
| 27 | * specific files using &xe_gt_debugfs_simple_show. |
| 28 | * |
| 29 | * It is assumed that those debugfs files will be created on directory entry |
| 30 | * which grandparent struct dentry d_inode->i_private points to &xe_gt. |
| 31 | * |
| 32 | * /sys/kernel/debug/dri/0/ |
| 33 | * ├── gt0 # dent->d_parent->d_parent (d_inode->i_private == gt) |
| 34 | * │ ├── uc # dent->d_parent |
| 35 | * │ │ ├── guc_info # dent |
| 36 | * │ │ ├── guc_... |
| 37 | * |
| 38 | * This function assumes that &m->private will be set to the &struct |
| 39 | * drm_info_node corresponding to the instance of the info on a given &struct |
| 40 | * drm_minor (see struct drm_info_list.show for details). |
| 41 | * |
| 42 | * This function also assumes that struct drm_info_list.data will point to the |
| 43 | * function code that will actually print a file content:: |
| 44 | * |
| 45 | * int (*print)(struct xe_guc *, struct drm_printer *) |
| 46 | * |
| 47 | * Example:: |
| 48 | * |
| 49 | * int foo(struct xe_guc *guc, struct drm_printer *p) |
| 50 | * { |
| 51 | * drm_printf(p, "enabled %d\n", guc->submission_state.enabled); |
| 52 | * return 0; |
| 53 | * } |
| 54 | * |
| 55 | * static const struct drm_info_list bar[] = { |
| 56 | * { name = "foo", .show = guc_debugfs_show, .data = foo }, |
| 57 | * }; |
| 58 | * |
| 59 | * parent = debugfs_create_dir("uc", gtdir); |
| 60 | * drm_debugfs_create_files(bar, ARRAY_SIZE(bar), parent, minor); |
| 61 | * |
| 62 | * Return: 0 on success or a negative error code on failure. |
| 63 | */ |
| 64 | static int guc_debugfs_show(struct seq_file *m, void *data) |
| 65 | { |
| 66 | struct drm_printer p = drm_seq_file_printer(f: m); |
| 67 | struct drm_info_node *node = m->private; |
| 68 | struct dentry *parent = node->dent->d_parent; |
| 69 | struct dentry *grandparent = parent->d_parent; |
| 70 | struct xe_gt *gt = grandparent->d_inode->i_private; |
| 71 | struct xe_device *xe = gt_to_xe(gt); |
| 72 | int (*print)(struct xe_guc *, struct drm_printer *) = node->info_ent->data; |
| 73 | int ret; |
| 74 | |
| 75 | xe_pm_runtime_get(xe); |
| 76 | ret = print(>->uc.guc, &p); |
| 77 | xe_pm_runtime_put(xe); |
| 78 | |
| 79 | return ret; |
| 80 | } |
| 81 | |
| 82 | static int guc_log(struct xe_guc *guc, struct drm_printer *p) |
| 83 | { |
| 84 | xe_guc_log_print(log: &guc->log, p); |
| 85 | return 0; |
| 86 | } |
| 87 | |
| 88 | static int guc_log_dmesg(struct xe_guc *guc, struct drm_printer *p) |
| 89 | { |
| 90 | xe_guc_log_print_dmesg(log: &guc->log); |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | static int guc_ctb(struct xe_guc *guc, struct drm_printer *p) |
| 95 | { |
| 96 | xe_guc_ct_print(ct: &guc->ct, p, want_ctb: true); |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | static int guc_pc(struct xe_guc *guc, struct drm_printer *p) |
| 101 | { |
| 102 | xe_guc_pc_print(pc: &guc->pc, p); |
| 103 | return 0; |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | * only for GuC debugfs files which can be safely used on the VF as well: |
| 108 | * - without access to the GuC privileged registers |
| 109 | * - without access to the PF specific GuC objects |
| 110 | */ |
| 111 | static const struct drm_info_list vf_safe_debugfs_list[] = { |
| 112 | { "guc_info" , .show = guc_debugfs_show, .data = xe_guc_print_info }, |
| 113 | { "guc_ctb" , .show = guc_debugfs_show, .data = guc_ctb }, |
| 114 | }; |
| 115 | |
| 116 | /* For GuC debugfs files that require the SLPC support */ |
| 117 | static const struct drm_info_list slpc_debugfs_list[] = { |
| 118 | { "guc_pc" , .show = guc_debugfs_show, .data = guc_pc }, |
| 119 | }; |
| 120 | |
| 121 | /* everything else should be added here */ |
| 122 | static const struct drm_info_list pf_only_debugfs_list[] = { |
| 123 | { "guc_log" , .show = guc_debugfs_show, .data = guc_log }, |
| 124 | { "guc_log_dmesg" , .show = guc_debugfs_show, .data = guc_log_dmesg }, |
| 125 | }; |
| 126 | |
| 127 | void xe_guc_debugfs_register(struct xe_guc *guc, struct dentry *parent) |
| 128 | { |
| 129 | struct xe_device *xe = guc_to_xe(guc); |
| 130 | struct drm_minor *minor = xe->drm.primary; |
| 131 | |
| 132 | drm_debugfs_create_files(files: vf_safe_debugfs_list, |
| 133 | ARRAY_SIZE(vf_safe_debugfs_list), |
| 134 | root: parent, minor); |
| 135 | |
| 136 | if (!IS_SRIOV_VF(xe)) { |
| 137 | drm_debugfs_create_files(files: pf_only_debugfs_list, |
| 138 | ARRAY_SIZE(pf_only_debugfs_list), |
| 139 | root: parent, minor); |
| 140 | |
| 141 | if (!xe->info.skip_guc_pc) |
| 142 | drm_debugfs_create_files(files: slpc_debugfs_list, |
| 143 | ARRAY_SIZE(slpc_debugfs_list), |
| 144 | root: parent, minor); |
| 145 | } |
| 146 | } |
| 147 | |