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_migration.h" 17 #include "xe_sriov_pf_provision.h" 18 #include "xe_sriov_pf_service.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 guard(xe_pm_runtime)(xe); 73 ret = call(xe); 74 } 75 if (ret < 0) 76 return ret; 77 return count; 78 } 79 80 #define DEFINE_SRIOV_ATTRIBUTE(OP) \ 81 static int OP##_show(struct seq_file *s, void *unused) \ 82 { \ 83 return 0; \ 84 } \ 85 static ssize_t OP##_write(struct file *file, const char __user *userbuf, \ 86 size_t count, loff_t *ppos) \ 87 { \ 88 return from_file_write_to_xe_call(file, userbuf, count, ppos, \ 89 xe_sriov_pf_##OP); \ 90 } \ 91 DEFINE_SHOW_STORE_ATTRIBUTE(OP) 92 93 static inline int xe_sriov_pf_restore_auto_provisioning(struct xe_device *xe) 94 { 95 return xe_sriov_pf_provision_set_mode(xe, XE_SRIOV_PROVISIONING_MODE_AUTO); 96 } 97 98 DEFINE_SRIOV_ATTRIBUTE(restore_auto_provisioning); 99 100 static int lockdown_vfs_enabling_open(struct inode *inode, struct file *file) 101 { 102 struct dentry *dent = file_dentry(file); 103 struct xe_device *xe = extract_xe(dent); 104 ssize_t ret; 105 106 ret = xe_sriov_pf_lockdown(xe); 107 if (ret < 0) 108 return ret; 109 110 file->private_data = xe; 111 return nonseekable_open(inode, file); 112 } 113 114 static int lockdown_vfs_enabling_release(struct inode *inode, struct file *file) 115 { 116 struct xe_device *xe = file->private_data; 117 118 xe_sriov_pf_end_lockdown(xe); 119 return 0; 120 } 121 122 static const struct file_operations lockdown_vfs_enabling_fops = { 123 .owner = THIS_MODULE, 124 .open = lockdown_vfs_enabling_open, 125 .release = lockdown_vfs_enabling_release, 126 }; 127 128 static void pf_populate_root(struct xe_device *xe, struct dentry *dent) 129 { 130 debugfs_create_file("restore_auto_provisioning", 0200, dent, xe, 131 &restore_auto_provisioning_fops); 132 debugfs_create_file("lockdown_vfs_enabling", 0400, dent, xe, 133 &lockdown_vfs_enabling_fops); 134 } 135 136 static int simple_show(struct seq_file *m, void *data) 137 { 138 struct drm_printer p = drm_seq_file_printer(m); 139 struct drm_info_node *node = m->private; 140 struct dentry *parent = node->dent->d_parent; 141 struct xe_device *xe = parent->d_inode->i_private; 142 void (*print)(struct xe_device *, struct drm_printer *) = node->info_ent->data; 143 144 print(xe, &p); 145 return 0; 146 } 147 148 static const struct drm_info_list debugfs_list[] = { 149 { .name = "vfs", .show = simple_show, .data = xe_sriov_pf_print_vfs_summary }, 150 { .name = "versions", .show = simple_show, .data = xe_sriov_pf_service_print_versions }, 151 }; 152 153 static void pf_populate_pf(struct xe_device *xe, struct dentry *pfdent) 154 { 155 struct drm_minor *minor = xe->drm.primary; 156 157 drm_debugfs_create_files(debugfs_list, ARRAY_SIZE(debugfs_list), pfdent, minor); 158 } 159 160 /* 161 * /sys/kernel/debug/dri/BDF/ 162 * ├── sriov 163 * │ ├── vf1 164 * │ │ ├── migration_data 165 * │ │ ├── pause 166 * │ │ ├── reset 167 * │ │ ├── resume 168 * │ │ ├── stop 169 * │ │ ├── save 170 * │ │ ├── restore 171 * │ │ : 172 * │ ├── vf2 173 * │ │ ├── ... 174 */ 175 176 static int from_file_read_to_vf_call(struct seq_file *s, 177 int (*call)(struct xe_device *, unsigned int)) 178 { 179 struct dentry *dent = file_dentry(s->file)->d_parent; 180 struct xe_device *xe = extract_xe(dent); 181 unsigned int vfid = extract_vfid(dent); 182 int ret; 183 184 xe_pm_runtime_get(xe); 185 ret = call(xe, vfid); 186 xe_pm_runtime_put(xe); 187 188 if (ret < 0) 189 return ret; 190 191 return 0; 192 } 193 194 static ssize_t from_file_write_to_vf_call(struct file *file, const char __user *userbuf, 195 size_t count, loff_t *ppos, 196 int (*call)(struct xe_device *, unsigned int)) 197 { 198 struct dentry *dent = file_dentry(file)->d_parent; 199 struct xe_device *xe = extract_xe(dent); 200 unsigned int vfid = extract_vfid(dent); 201 bool yes; 202 int ret; 203 204 if (*ppos) 205 return -EINVAL; 206 ret = kstrtobool_from_user(userbuf, count, &yes); 207 if (ret < 0) 208 return ret; 209 if (yes) { 210 guard(xe_pm_runtime)(xe); 211 ret = call(xe, vfid); 212 } 213 if (ret < 0) 214 return ret; 215 return count; 216 } 217 218 #define DEFINE_VF_CONTROL_ATTRIBUTE(OP) \ 219 static int OP##_show(struct seq_file *s, void *unused) \ 220 { \ 221 return 0; \ 222 } \ 223 static ssize_t OP##_write(struct file *file, const char __user *userbuf, \ 224 size_t count, loff_t *ppos) \ 225 { \ 226 return from_file_write_to_vf_call(file, userbuf, count, ppos, \ 227 xe_sriov_pf_control_##OP); \ 228 } \ 229 DEFINE_SHOW_STORE_ATTRIBUTE(OP) 230 231 #define DEFINE_VF_CONTROL_ATTRIBUTE_RW(OP) \ 232 static int OP##_show(struct seq_file *s, void *unused) \ 233 { \ 234 return from_file_read_to_vf_call(s, \ 235 xe_sriov_pf_control_finish_##OP); \ 236 } \ 237 static ssize_t OP##_write(struct file *file, const char __user *userbuf, \ 238 size_t count, loff_t *ppos) \ 239 { \ 240 return from_file_write_to_vf_call(file, userbuf, count, ppos, \ 241 xe_sriov_pf_control_trigger_##OP); \ 242 } \ 243 DEFINE_SHOW_STORE_ATTRIBUTE(OP) 244 245 DEFINE_VF_CONTROL_ATTRIBUTE(pause_vf); 246 DEFINE_VF_CONTROL_ATTRIBUTE(resume_vf); 247 DEFINE_VF_CONTROL_ATTRIBUTE(stop_vf); 248 DEFINE_VF_CONTROL_ATTRIBUTE(reset_vf); 249 DEFINE_VF_CONTROL_ATTRIBUTE_RW(save_vf); 250 DEFINE_VF_CONTROL_ATTRIBUTE_RW(restore_vf); 251 252 static ssize_t data_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) 253 { 254 struct dentry *dent = file_dentry(file)->d_parent; 255 struct xe_device *xe = extract_xe(dent); 256 unsigned int vfid = extract_vfid(dent); 257 258 if (*pos) 259 return -ESPIPE; 260 261 return xe_sriov_pf_migration_write(xe, vfid, buf, count); 262 } 263 264 static ssize_t data_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 265 { 266 struct dentry *dent = file_dentry(file)->d_parent; 267 struct xe_device *xe = extract_xe(dent); 268 unsigned int vfid = extract_vfid(dent); 269 270 if (*ppos) 271 return -ESPIPE; 272 273 return xe_sriov_pf_migration_read(xe, vfid, buf, count); 274 } 275 276 static const struct file_operations data_vf_fops = { 277 .owner = THIS_MODULE, 278 .open = simple_open, 279 .write = data_write, 280 .read = data_read, 281 .llseek = default_llseek, 282 }; 283 284 static ssize_t size_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) 285 { 286 struct dentry *dent = file_dentry(file)->d_parent; 287 struct xe_device *xe = extract_xe(dent); 288 unsigned int vfid = extract_vfid(dent); 289 char buf[21]; 290 ssize_t ret; 291 int len; 292 293 xe_pm_runtime_get(xe); 294 ret = xe_sriov_pf_migration_size(xe, vfid); 295 xe_pm_runtime_put(xe); 296 if (ret < 0) 297 return ret; 298 299 len = scnprintf(buf, sizeof(buf), "%zd\n", ret); 300 301 return simple_read_from_buffer(ubuf, count, ppos, buf, len); 302 } 303 304 static const struct file_operations size_vf_fops = { 305 .owner = THIS_MODULE, 306 .open = simple_open, 307 .read = size_read, 308 .llseek = default_llseek, 309 }; 310 311 static void pf_populate_vf(struct xe_device *xe, struct dentry *vfdent) 312 { 313 debugfs_create_file("pause", 0200, vfdent, xe, &pause_vf_fops); 314 debugfs_create_file("resume", 0200, vfdent, xe, &resume_vf_fops); 315 debugfs_create_file("stop", 0200, vfdent, xe, &stop_vf_fops); 316 debugfs_create_file("reset", 0200, vfdent, xe, &reset_vf_fops); 317 debugfs_create_file("save", 0600, vfdent, xe, &save_vf_fops); 318 debugfs_create_file("restore", 0600, vfdent, xe, &restore_vf_fops); 319 debugfs_create_file("migration_data", 0600, vfdent, xe, &data_vf_fops); 320 debugfs_create_file("migration_size", 0400, vfdent, xe, &size_vf_fops); 321 } 322 323 static void pf_populate_with_tiles(struct xe_device *xe, struct dentry *dent, unsigned int vfid) 324 { 325 struct xe_tile *tile; 326 unsigned int id; 327 328 for_each_tile(tile, xe, id) 329 xe_tile_sriov_pf_debugfs_populate(tile, dent, vfid); 330 } 331 332 /** 333 * xe_sriov_pf_debugfs_register - Register PF debugfs attributes. 334 * @xe: the &xe_device 335 * @root: the root &dentry 336 * 337 * Create separate directory that will contain all SR-IOV related files, 338 * organized per each SR-IOV function (PF, VF1, VF2, ..., VFn). 339 */ 340 void xe_sriov_pf_debugfs_register(struct xe_device *xe, struct dentry *root) 341 { 342 int totalvfs = xe_sriov_pf_get_totalvfs(xe); 343 struct dentry *pfdent; 344 struct dentry *vfdent; 345 struct dentry *dent; 346 char vfname[16]; /* should be more than enough for "vf%u\0" and VFID(UINT_MAX) */ 347 unsigned int n; 348 349 /* 350 * /sys/kernel/debug/dri/BDF/ 351 * ├── sriov # d_inode->i_private = (xe_device*) 352 * │ ├── ... 353 */ 354 dent = debugfs_create_dir("sriov", root); 355 if (IS_ERR(dent)) 356 return; 357 dent->d_inode->i_private = xe; 358 359 pf_populate_root(xe, dent); 360 361 /* 362 * /sys/kernel/debug/dri/BDF/ 363 * ├── sriov # d_inode->i_private = (xe_device*) 364 * │ ├── pf # d_inode->i_private = (xe_device*) 365 * │ │ ├── ... 366 */ 367 pfdent = debugfs_create_dir("pf", dent); 368 if (IS_ERR(pfdent)) 369 return; 370 pfdent->d_inode->i_private = xe; 371 372 pf_populate_pf(xe, pfdent); 373 pf_populate_with_tiles(xe, pfdent, PFID); 374 375 /* 376 * /sys/kernel/debug/dri/BDF/ 377 * ├── sriov # d_inode->i_private = (xe_device*) 378 * │ ├── vf1 # d_inode->i_private = VFID(1) 379 * │ ├── vf2 # d_inode->i_private = VFID(2) 380 * │ ├── ... 381 */ 382 for (n = 1; n <= totalvfs; n++) { 383 snprintf(vfname, sizeof(vfname), "vf%u", VFID(n)); 384 vfdent = debugfs_create_dir(vfname, dent); 385 if (IS_ERR(vfdent)) 386 return; 387 vfdent->d_inode->i_private = (void *)(uintptr_t)VFID(n); 388 389 pf_populate_vf(xe, vfdent); 390 pf_populate_with_tiles(xe, vfdent, VFID(n)); 391 } 392 } 393