1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/debugfs.h> 7 #include <drm/drm_debugfs.h> 8 9 #include "xe_device.h" 10 #include "xe_device_types.h" 11 #include "xe_pm.h" 12 #include "xe_sriov_pf.h" 13 #include "xe_sriov_pf_control.h" 14 #include "xe_sriov_pf_debugfs.h" 15 #include "xe_sriov_pf_helpers.h" 16 #include "xe_sriov_pf_provision.h" 17 #include "xe_sriov_pf_service.h" 18 #include "xe_sriov_printk.h" 19 #include "xe_tile_sriov_pf_debugfs.h" 20 21 /* 22 * /sys/kernel/debug/dri/BDF/ 23 * ├── sriov # d_inode->i_private = (xe_device*) 24 * │ ├── pf # d_inode->i_private = (xe_device*) 25 * │ ├── vf1 # d_inode->i_private = VFID(1) 26 * : : 27 * │ ├── vfN # d_inode->i_private = VFID(N) 28 */ 29 30 static void *extract_priv(struct dentry *d) 31 { 32 return d->d_inode->i_private; 33 } 34 35 static struct xe_device *extract_xe(struct dentry *d) 36 { 37 return extract_priv(d->d_parent); 38 } 39 40 static unsigned int extract_vfid(struct dentry *d) 41 { 42 void *p = extract_priv(d); 43 44 return p == extract_xe(d) ? PFID : (uintptr_t)p; 45 } 46 47 /* 48 * /sys/kernel/debug/dri/BDF/ 49 * ├── sriov 50 * │ ├── restore_auto_provisioning 51 * │ : 52 * │ ├── pf/ 53 * │ ├── vf1 54 * │ │ ├── ... 55 */ 56 57 static ssize_t from_file_write_to_xe_call(struct file *file, const char __user *userbuf, 58 size_t count, loff_t *ppos, 59 int (*call)(struct xe_device *)) 60 { 61 struct dentry *dent = file_dentry(file); 62 struct xe_device *xe = extract_xe(dent); 63 bool yes; 64 int ret; 65 66 if (*ppos) 67 return -EINVAL; 68 ret = kstrtobool_from_user(userbuf, count, &yes); 69 if (ret < 0) 70 return ret; 71 if (yes) { 72 xe_pm_runtime_get(xe); 73 ret = call(xe); 74 xe_pm_runtime_put(xe); 75 } 76 if (ret < 0) 77 return ret; 78 return count; 79 } 80 81 #define DEFINE_SRIOV_ATTRIBUTE(OP) \ 82 static int OP##_show(struct seq_file *s, void *unused) \ 83 { \ 84 return 0; \ 85 } \ 86 static ssize_t OP##_write(struct file *file, const char __user *userbuf, \ 87 size_t count, loff_t *ppos) \ 88 { \ 89 return from_file_write_to_xe_call(file, userbuf, count, ppos, \ 90 xe_sriov_pf_##OP); \ 91 } \ 92 DEFINE_SHOW_STORE_ATTRIBUTE(OP) 93 94 static inline int xe_sriov_pf_restore_auto_provisioning(struct xe_device *xe) 95 { 96 return xe_sriov_pf_provision_set_mode(xe, XE_SRIOV_PROVISIONING_MODE_AUTO); 97 } 98 99 DEFINE_SRIOV_ATTRIBUTE(restore_auto_provisioning); 100 101 static void pf_populate_root(struct xe_device *xe, struct dentry *dent) 102 { 103 debugfs_create_file("restore_auto_provisioning", 0200, dent, xe, 104 &restore_auto_provisioning_fops); 105 } 106 107 static int simple_show(struct seq_file *m, void *data) 108 { 109 struct drm_printer p = drm_seq_file_printer(m); 110 struct drm_info_node *node = m->private; 111 struct dentry *parent = node->dent->d_parent; 112 struct xe_device *xe = parent->d_inode->i_private; 113 void (*print)(struct xe_device *, struct drm_printer *) = node->info_ent->data; 114 115 print(xe, &p); 116 return 0; 117 } 118 119 static const struct drm_info_list debugfs_list[] = { 120 { .name = "vfs", .show = simple_show, .data = xe_sriov_pf_print_vfs_summary }, 121 { .name = "versions", .show = simple_show, .data = xe_sriov_pf_service_print_versions }, 122 }; 123 124 static void pf_populate_pf(struct xe_device *xe, struct dentry *pfdent) 125 { 126 struct drm_minor *minor = xe->drm.primary; 127 128 drm_debugfs_create_files(debugfs_list, ARRAY_SIZE(debugfs_list), pfdent, minor); 129 } 130 131 /* 132 * /sys/kernel/debug/dri/BDF/ 133 * ├── sriov 134 * │ ├── vf1 135 * │ │ ├── pause 136 * │ │ ├── reset 137 * │ │ ├── resume 138 * │ │ ├── stop 139 * │ │ : 140 * │ ├── vf2 141 * │ │ ├── ... 142 */ 143 144 static ssize_t from_file_write_to_vf_call(struct file *file, const char __user *userbuf, 145 size_t count, loff_t *ppos, 146 int (*call)(struct xe_device *, unsigned int)) 147 { 148 struct dentry *dent = file_dentry(file)->d_parent; 149 struct xe_device *xe = extract_xe(dent); 150 unsigned int vfid = extract_vfid(dent); 151 bool yes; 152 int ret; 153 154 if (*ppos) 155 return -EINVAL; 156 ret = kstrtobool_from_user(userbuf, count, &yes); 157 if (ret < 0) 158 return ret; 159 if (yes) { 160 xe_pm_runtime_get(xe); 161 ret = call(xe, vfid); 162 xe_pm_runtime_put(xe); 163 } 164 if (ret < 0) 165 return ret; 166 return count; 167 } 168 169 #define DEFINE_VF_CONTROL_ATTRIBUTE(OP) \ 170 static int OP##_show(struct seq_file *s, void *unused) \ 171 { \ 172 return 0; \ 173 } \ 174 static ssize_t OP##_write(struct file *file, const char __user *userbuf, \ 175 size_t count, loff_t *ppos) \ 176 { \ 177 return from_file_write_to_vf_call(file, userbuf, count, ppos, \ 178 xe_sriov_pf_control_##OP); \ 179 } \ 180 DEFINE_SHOW_STORE_ATTRIBUTE(OP) 181 182 DEFINE_VF_CONTROL_ATTRIBUTE(pause_vf); 183 DEFINE_VF_CONTROL_ATTRIBUTE(resume_vf); 184 DEFINE_VF_CONTROL_ATTRIBUTE(stop_vf); 185 DEFINE_VF_CONTROL_ATTRIBUTE(reset_vf); 186 187 static void pf_populate_vf(struct xe_device *xe, struct dentry *vfdent) 188 { 189 debugfs_create_file("pause", 0200, vfdent, xe, &pause_vf_fops); 190 debugfs_create_file("resume", 0200, vfdent, xe, &resume_vf_fops); 191 debugfs_create_file("stop", 0200, vfdent, xe, &stop_vf_fops); 192 debugfs_create_file("reset", 0200, vfdent, xe, &reset_vf_fops); 193 } 194 195 static void pf_populate_with_tiles(struct xe_device *xe, struct dentry *dent, unsigned int vfid) 196 { 197 struct xe_tile *tile; 198 unsigned int id; 199 200 for_each_tile(tile, xe, id) 201 xe_tile_sriov_pf_debugfs_populate(tile, dent, vfid); 202 } 203 204 /** 205 * xe_sriov_pf_debugfs_register - Register PF debugfs attributes. 206 * @xe: the &xe_device 207 * @root: the root &dentry 208 * 209 * Create separate directory that will contain all SR-IOV related files, 210 * organized per each SR-IOV function (PF, VF1, VF2, ..., VFn). 211 */ 212 void xe_sriov_pf_debugfs_register(struct xe_device *xe, struct dentry *root) 213 { 214 int totalvfs = xe_sriov_pf_get_totalvfs(xe); 215 struct dentry *pfdent; 216 struct dentry *vfdent; 217 struct dentry *dent; 218 char vfname[16]; /* should be more than enough for "vf%u\0" and VFID(UINT_MAX) */ 219 unsigned int n; 220 221 /* 222 * /sys/kernel/debug/dri/BDF/ 223 * ├── sriov # d_inode->i_private = (xe_device*) 224 * │ ├── ... 225 */ 226 dent = debugfs_create_dir("sriov", root); 227 if (IS_ERR(dent)) 228 return; 229 dent->d_inode->i_private = xe; 230 231 pf_populate_root(xe, dent); 232 233 /* 234 * /sys/kernel/debug/dri/BDF/ 235 * ├── sriov # d_inode->i_private = (xe_device*) 236 * │ ├── pf # d_inode->i_private = (xe_device*) 237 * │ │ ├── ... 238 */ 239 pfdent = debugfs_create_dir("pf", dent); 240 if (IS_ERR(pfdent)) 241 return; 242 pfdent->d_inode->i_private = xe; 243 244 pf_populate_pf(xe, pfdent); 245 pf_populate_with_tiles(xe, pfdent, PFID); 246 247 /* 248 * /sys/kernel/debug/dri/BDF/ 249 * ├── sriov # d_inode->i_private = (xe_device*) 250 * │ ├── vf1 # d_inode->i_private = VFID(1) 251 * │ ├── vf2 # d_inode->i_private = VFID(2) 252 * │ ├── ... 253 */ 254 for (n = 1; n <= totalvfs; n++) { 255 snprintf(vfname, sizeof(vfname), "vf%u", VFID(n)); 256 vfdent = debugfs_create_dir(vfname, dent); 257 if (IS_ERR(vfdent)) 258 return; 259 vfdent->d_inode->i_private = (void *)(uintptr_t)VFID(n); 260 261 pf_populate_vf(xe, vfdent); 262 pf_populate_with_tiles(xe, vfdent, VFID(n)); 263 } 264 } 265