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