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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16-rc2 596 lines 17 kB view raw
1// SPDX-License-Identifier: MIT 2/* 3 * Copyright © 2023-2024 Intel Corporation 4 */ 5 6#include <linux/debugfs.h> 7 8#include <drm/drm_print.h> 9#include <drm/drm_debugfs.h> 10 11#include "xe_bo.h" 12#include "xe_debugfs.h" 13#include "xe_device.h" 14#include "xe_gt.h" 15#include "xe_gt_debugfs.h" 16#include "xe_gt_sriov_pf_config.h" 17#include "xe_gt_sriov_pf_control.h" 18#include "xe_gt_sriov_pf_debugfs.h" 19#include "xe_gt_sriov_pf_helpers.h" 20#include "xe_gt_sriov_pf_migration.h" 21#include "xe_gt_sriov_pf_monitor.h" 22#include "xe_gt_sriov_pf_policy.h" 23#include "xe_gt_sriov_pf_service.h" 24#include "xe_pm.h" 25 26/* 27 * /sys/kernel/debug/dri/0/ 28 * ├── gt0 # d_inode->i_private = gt 29 * │   ├── pf # d_inode->i_private = gt 30 * │   ├── vf1 # d_inode->i_private = VFID(1) 31 * :   : 32 * │   ├── vfN # d_inode->i_private = VFID(N) 33 */ 34 35static void *extract_priv(struct dentry *d) 36{ 37 return d->d_inode->i_private; 38} 39 40static struct xe_gt *extract_gt(struct dentry *d) 41{ 42 return extract_priv(d->d_parent); 43} 44 45static unsigned int extract_vfid(struct dentry *d) 46{ 47 return extract_priv(d) == extract_gt(d) ? PFID : (uintptr_t)extract_priv(d); 48} 49 50/* 51 * /sys/kernel/debug/dri/0/ 52 * ├── gt0 53 * │   ├── pf 54 * │   │   ├── contexts_provisioned 55 * │   │   ├── doorbells_provisioned 56 * │   │   ├── runtime_registers 57 * │   │   ├── negotiated_versions 58 * │   │   ├── adverse_events 59 * ├── gt1 60 * │   ├── pf 61 * │   │   ├── ... 62 */ 63 64static const struct drm_info_list pf_info[] = { 65 { 66 "contexts_provisioned", 67 .show = xe_gt_debugfs_simple_show, 68 .data = xe_gt_sriov_pf_config_print_ctxs, 69 }, 70 { 71 "doorbells_provisioned", 72 .show = xe_gt_debugfs_simple_show, 73 .data = xe_gt_sriov_pf_config_print_dbs, 74 }, 75 { 76 "runtime_registers", 77 .show = xe_gt_debugfs_simple_show, 78 .data = xe_gt_sriov_pf_service_print_runtime, 79 }, 80 { 81 "negotiated_versions", 82 .show = xe_gt_debugfs_simple_show, 83 .data = xe_gt_sriov_pf_service_print_version, 84 }, 85 { 86 "adverse_events", 87 .show = xe_gt_debugfs_simple_show, 88 .data = xe_gt_sriov_pf_monitor_print_events, 89 }, 90}; 91 92/* 93 * /sys/kernel/debug/dri/0/ 94 * ├── gt0 95 * │   ├── pf 96 * │   │   ├── ggtt_available 97 * │   │   ├── ggtt_provisioned 98 */ 99 100static const struct drm_info_list pf_ggtt_info[] = { 101 { 102 "ggtt_available", 103 .show = xe_gt_debugfs_simple_show, 104 .data = xe_gt_sriov_pf_config_print_available_ggtt, 105 }, 106 { 107 "ggtt_provisioned", 108 .show = xe_gt_debugfs_simple_show, 109 .data = xe_gt_sriov_pf_config_print_ggtt, 110 }, 111}; 112 113/* 114 * /sys/kernel/debug/dri/0/ 115 * ├── gt0 116 * │   ├── pf 117 * │   │   ├── lmem_provisioned 118 */ 119 120static const struct drm_info_list pf_lmem_info[] = { 121 { 122 "lmem_provisioned", 123 .show = xe_gt_debugfs_simple_show, 124 .data = xe_gt_sriov_pf_config_print_lmem, 125 }, 126}; 127 128/* 129 * /sys/kernel/debug/dri/0/ 130 * ├── gt0 131 * │   ├── pf 132 * │   │   ├── reset_engine 133 * │   │   ├── sample_period 134 * │   │   ├── sched_if_idle 135 */ 136 137#define DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(POLICY, TYPE, FORMAT) \ 138 \ 139static int POLICY##_set(void *data, u64 val) \ 140{ \ 141 struct xe_gt *gt = extract_gt(data); \ 142 struct xe_device *xe = gt_to_xe(gt); \ 143 int err; \ 144 \ 145 if (val > (TYPE)~0ull) \ 146 return -EOVERFLOW; \ 147 \ 148 xe_pm_runtime_get(xe); \ 149 err = xe_gt_sriov_pf_policy_set_##POLICY(gt, val); \ 150 xe_pm_runtime_put(xe); \ 151 \ 152 return err; \ 153} \ 154 \ 155static int POLICY##_get(void *data, u64 *val) \ 156{ \ 157 struct xe_gt *gt = extract_gt(data); \ 158 \ 159 *val = xe_gt_sriov_pf_policy_get_##POLICY(gt); \ 160 return 0; \ 161} \ 162 \ 163DEFINE_DEBUGFS_ATTRIBUTE(POLICY##_fops, POLICY##_get, POLICY##_set, FORMAT) 164 165DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(reset_engine, bool, "%llu\n"); 166DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(sched_if_idle, bool, "%llu\n"); 167DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(sample_period, u32, "%llu\n"); 168 169static void pf_add_policy_attrs(struct xe_gt *gt, struct dentry *parent) 170{ 171 xe_gt_assert(gt, gt == extract_gt(parent)); 172 xe_gt_assert(gt, PFID == extract_vfid(parent)); 173 174 debugfs_create_file_unsafe("reset_engine", 0644, parent, parent, &reset_engine_fops); 175 debugfs_create_file_unsafe("sched_if_idle", 0644, parent, parent, &sched_if_idle_fops); 176 debugfs_create_file_unsafe("sample_period_ms", 0644, parent, parent, &sample_period_fops); 177} 178 179/* 180 * /sys/kernel/debug/dri/0/ 181 * ├── gt0 182 * │   ├── pf 183 * │   │   ├── ggtt_spare 184 * │   │   ├── lmem_spare 185 * │   │   ├── doorbells_spare 186 * │   │   ├── contexts_spare 187 * │   │   ├── exec_quantum_ms 188 * │   │   ├── preempt_timeout_us 189 * │   │   ├── sched_priority 190 * │   ├── vf1 191 * │   │   ├── ggtt_quota 192 * │   │   ├── lmem_quota 193 * │   │   ├── doorbells_quota 194 * │   │   ├── contexts_quota 195 * │   │   ├── exec_quantum_ms 196 * │   │   ├── preempt_timeout_us 197 * │   │   ├── sched_priority 198 */ 199 200#define DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(CONFIG, TYPE, FORMAT) \ 201 \ 202static int CONFIG##_set(void *data, u64 val) \ 203{ \ 204 struct xe_gt *gt = extract_gt(data); \ 205 unsigned int vfid = extract_vfid(data); \ 206 struct xe_device *xe = gt_to_xe(gt); \ 207 int err; \ 208 \ 209 if (val > (TYPE)~0ull) \ 210 return -EOVERFLOW; \ 211 \ 212 xe_pm_runtime_get(xe); \ 213 err = xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val); \ 214 xe_pm_runtime_put(xe); \ 215 \ 216 return err; \ 217} \ 218 \ 219static int CONFIG##_get(void *data, u64 *val) \ 220{ \ 221 struct xe_gt *gt = extract_gt(data); \ 222 unsigned int vfid = extract_vfid(data); \ 223 \ 224 *val = xe_gt_sriov_pf_config_get_##CONFIG(gt, vfid); \ 225 return 0; \ 226} \ 227 \ 228DEFINE_DEBUGFS_ATTRIBUTE(CONFIG##_fops, CONFIG##_get, CONFIG##_set, FORMAT) 229 230DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(ggtt, u64, "%llu\n"); 231DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(lmem, u64, "%llu\n"); 232DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(ctxs, u32, "%llu\n"); 233DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(dbs, u32, "%llu\n"); 234DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(exec_quantum, u32, "%llu\n"); 235DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(preempt_timeout, u32, "%llu\n"); 236DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(sched_priority, u32, "%llu\n"); 237 238/* 239 * /sys/kernel/debug/dri/0/ 240 * ├── gt0 241 * │   ├── pf 242 * │   │   ├── threshold_cat_error_count 243 * │   │   ├── threshold_doorbell_time_us 244 * │   │   ├── threshold_engine_reset_count 245 * │   │   ├── threshold_guc_time_us 246 * │   │   ├── threshold_irq_time_us 247 * │   │   ├── threshold_page_fault_count 248 * │   ├── vf1 249 * │   │   ├── threshold_cat_error_count 250 * │   │   ├── threshold_doorbell_time_us 251 * │   │   ├── threshold_engine_reset_count 252 * │   │   ├── threshold_guc_time_us 253 * │   │   ├── threshold_irq_time_us 254 * │   │   ├── threshold_page_fault_count 255 */ 256 257static int set_threshold(void *data, u64 val, enum xe_guc_klv_threshold_index index) 258{ 259 struct xe_gt *gt = extract_gt(data); 260 unsigned int vfid = extract_vfid(data); 261 struct xe_device *xe = gt_to_xe(gt); 262 int err; 263 264 if (val > (u32)~0ull) 265 return -EOVERFLOW; 266 267 xe_pm_runtime_get(xe); 268 err = xe_gt_sriov_pf_config_set_threshold(gt, vfid, index, val); 269 xe_pm_runtime_put(xe); 270 271 return err; 272} 273 274static int get_threshold(void *data, u64 *val, enum xe_guc_klv_threshold_index index) 275{ 276 struct xe_gt *gt = extract_gt(data); 277 unsigned int vfid = extract_vfid(data); 278 279 *val = xe_gt_sriov_pf_config_get_threshold(gt, vfid, index); 280 return 0; 281} 282 283#define DEFINE_SRIOV_GT_THRESHOLD_DEBUGFS_ATTRIBUTE(THRESHOLD, INDEX) \ 284 \ 285static int THRESHOLD##_set(void *data, u64 val) \ 286{ \ 287 return set_threshold(data, val, INDEX); \ 288} \ 289 \ 290static int THRESHOLD##_get(void *data, u64 *val) \ 291{ \ 292 return get_threshold(data, val, INDEX); \ 293} \ 294 \ 295DEFINE_DEBUGFS_ATTRIBUTE(THRESHOLD##_fops, THRESHOLD##_get, THRESHOLD##_set, "%llu\n") 296 297/* generate all threshold attributes */ 298#define define_threshold_attribute(TAG, NAME, ...) \ 299 DEFINE_SRIOV_GT_THRESHOLD_DEBUGFS_ATTRIBUTE(NAME, MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG)); 300MAKE_XE_GUC_KLV_THRESHOLDS_SET(define_threshold_attribute) 301#undef define_threshold_attribute 302 303static void pf_add_config_attrs(struct xe_gt *gt, struct dentry *parent, unsigned int vfid) 304{ 305 xe_gt_assert(gt, gt == extract_gt(parent)); 306 xe_gt_assert(gt, vfid == extract_vfid(parent)); 307 308 if (!xe_gt_is_media_type(gt)) { 309 debugfs_create_file_unsafe(vfid ? "ggtt_quota" : "ggtt_spare", 310 0644, parent, parent, &ggtt_fops); 311 if (IS_DGFX(gt_to_xe(gt))) 312 debugfs_create_file_unsafe(vfid ? "lmem_quota" : "lmem_spare", 313 0644, parent, parent, &lmem_fops); 314 } 315 debugfs_create_file_unsafe(vfid ? "doorbells_quota" : "doorbells_spare", 316 0644, parent, parent, &dbs_fops); 317 debugfs_create_file_unsafe(vfid ? "contexts_quota" : "contexts_spare", 318 0644, parent, parent, &ctxs_fops); 319 debugfs_create_file_unsafe("exec_quantum_ms", 0644, parent, parent, 320 &exec_quantum_fops); 321 debugfs_create_file_unsafe("preempt_timeout_us", 0644, parent, parent, 322 &preempt_timeout_fops); 323 debugfs_create_file_unsafe("sched_priority", 0644, parent, parent, 324 &sched_priority_fops); 325 326 /* register all threshold attributes */ 327#define register_threshold_attribute(TAG, NAME, ...) \ 328 debugfs_create_file_unsafe("threshold_" #NAME, 0644, parent, parent, \ 329 &NAME##_fops); 330 MAKE_XE_GUC_KLV_THRESHOLDS_SET(register_threshold_attribute) 331#undef register_threshold_attribute 332} 333 334/* 335 * /sys/kernel/debug/dri/0/ 336 * ├── gt0 337 * │   ├── vf1 338 * │   │   ├── control { stop, pause, resume } 339 */ 340 341static const struct { 342 const char *cmd; 343 int (*fn)(struct xe_gt *gt, unsigned int vfid); 344} control_cmds[] = { 345 { "stop", xe_gt_sriov_pf_control_stop_vf }, 346 { "pause", xe_gt_sriov_pf_control_pause_vf }, 347 { "resume", xe_gt_sriov_pf_control_resume_vf }, 348#ifdef CONFIG_DRM_XE_DEBUG_SRIOV 349 { "restore!", xe_gt_sriov_pf_migration_restore_guc_state }, 350#endif 351}; 352 353static ssize_t control_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) 354{ 355 struct dentry *dent = file_dentry(file); 356 struct dentry *parent = dent->d_parent; 357 struct xe_gt *gt = extract_gt(parent); 358 struct xe_device *xe = gt_to_xe(gt); 359 unsigned int vfid = extract_vfid(parent); 360 int ret = -EINVAL; 361 char cmd[32]; 362 size_t n; 363 364 xe_gt_assert(gt, vfid); 365 xe_gt_sriov_pf_assert_vfid(gt, vfid); 366 367 if (*pos) 368 return -ESPIPE; 369 370 if (count > sizeof(cmd) - 1) 371 return -EINVAL; 372 373 ret = simple_write_to_buffer(cmd, sizeof(cmd) - 1, pos, buf, count); 374 if (ret < 0) 375 return ret; 376 cmd[ret] = '\0'; 377 378 for (n = 0; n < ARRAY_SIZE(control_cmds); n++) { 379 xe_gt_assert(gt, sizeof(cmd) > strlen(control_cmds[n].cmd)); 380 381 if (sysfs_streq(cmd, control_cmds[n].cmd)) { 382 xe_pm_runtime_get(xe); 383 ret = control_cmds[n].fn ? (*control_cmds[n].fn)(gt, vfid) : 0; 384 xe_pm_runtime_put(xe); 385 break; 386 } 387 } 388 389 return (ret < 0) ? ret : count; 390} 391 392static ssize_t control_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 393{ 394 char help[128]; 395 size_t n; 396 397 help[0] = '\0'; 398 for (n = 0; n < ARRAY_SIZE(control_cmds); n++) { 399 strlcat(help, control_cmds[n].cmd, sizeof(help)); 400 strlcat(help, "\n", sizeof(help)); 401 } 402 403 return simple_read_from_buffer(buf, count, ppos, help, strlen(help)); 404} 405 406static const struct file_operations control_ops = { 407 .owner = THIS_MODULE, 408 .open = simple_open, 409 .write = control_write, 410 .read = control_read, 411 .llseek = default_llseek, 412}; 413 414/* 415 * /sys/kernel/debug/dri/0/ 416 * ├── gt0 417 * │   ├── vf1 418 * │   │   ├── guc_state 419 */ 420static ssize_t guc_state_read(struct file *file, char __user *buf, 421 size_t count, loff_t *pos) 422{ 423 struct dentry *dent = file_dentry(file); 424 struct dentry *parent = dent->d_parent; 425 struct xe_gt *gt = extract_gt(parent); 426 unsigned int vfid = extract_vfid(parent); 427 428 return xe_gt_sriov_pf_migration_read_guc_state(gt, vfid, buf, count, pos); 429} 430 431static ssize_t guc_state_write(struct file *file, const char __user *buf, 432 size_t count, loff_t *pos) 433{ 434 struct dentry *dent = file_dentry(file); 435 struct dentry *parent = dent->d_parent; 436 struct xe_gt *gt = extract_gt(parent); 437 unsigned int vfid = extract_vfid(parent); 438 439 if (*pos) 440 return -EINVAL; 441 442 return xe_gt_sriov_pf_migration_write_guc_state(gt, vfid, buf, count); 443} 444 445static const struct file_operations guc_state_ops = { 446 .owner = THIS_MODULE, 447 .read = guc_state_read, 448 .write = guc_state_write, 449 .llseek = default_llseek, 450}; 451 452/* 453 * /sys/kernel/debug/dri/0/ 454 * ├── gt0 455 * │   ├── vf1 456 * │   │   ├── config_blob 457 */ 458static ssize_t config_blob_read(struct file *file, char __user *buf, 459 size_t count, loff_t *pos) 460{ 461 struct dentry *dent = file_dentry(file); 462 struct dentry *parent = dent->d_parent; 463 struct xe_gt *gt = extract_gt(parent); 464 unsigned int vfid = extract_vfid(parent); 465 ssize_t ret; 466 void *tmp; 467 468 ret = xe_gt_sriov_pf_config_save(gt, vfid, NULL, 0); 469 if (!ret) 470 return -ENODATA; 471 if (ret < 0) 472 return ret; 473 474 tmp = kzalloc(ret, GFP_KERNEL); 475 if (!tmp) 476 return -ENOMEM; 477 478 ret = xe_gt_sriov_pf_config_save(gt, vfid, tmp, ret); 479 if (ret > 0) 480 ret = simple_read_from_buffer(buf, count, pos, tmp, ret); 481 482 kfree(tmp); 483 return ret; 484} 485 486static ssize_t config_blob_write(struct file *file, const char __user *buf, 487 size_t count, loff_t *pos) 488{ 489 struct dentry *dent = file_dentry(file); 490 struct dentry *parent = dent->d_parent; 491 struct xe_gt *gt = extract_gt(parent); 492 unsigned int vfid = extract_vfid(parent); 493 ssize_t ret; 494 void *tmp; 495 496 if (*pos) 497 return -EINVAL; 498 499 if (!count) 500 return -ENODATA; 501 502 if (count > SZ_4K) 503 return -EINVAL; 504 505 tmp = kzalloc(count, GFP_KERNEL); 506 if (!tmp) 507 return -ENOMEM; 508 509 if (copy_from_user(tmp, buf, count)) { 510 ret = -EFAULT; 511 } else { 512 ret = xe_gt_sriov_pf_config_restore(gt, vfid, tmp, count); 513 if (!ret) 514 ret = count; 515 } 516 kfree(tmp); 517 return ret; 518} 519 520static const struct file_operations config_blob_ops = { 521 .owner = THIS_MODULE, 522 .read = config_blob_read, 523 .write = config_blob_write, 524 .llseek = default_llseek, 525}; 526 527/** 528 * xe_gt_sriov_pf_debugfs_register - Register SR-IOV PF specific entries in GT debugfs. 529 * @gt: the &xe_gt to register 530 * @root: the &dentry that represents the GT directory 531 * 532 * Register SR-IOV PF entries that are GT related and must be shown under GT debugfs. 533 */ 534void xe_gt_sriov_pf_debugfs_register(struct xe_gt *gt, struct dentry *root) 535{ 536 struct xe_device *xe = gt_to_xe(gt); 537 struct drm_minor *minor = xe->drm.primary; 538 int n, totalvfs = xe_sriov_pf_get_totalvfs(xe); 539 struct dentry *pfdentry; 540 struct dentry *vfdentry; 541 char buf[14]; /* should be enough up to "vf%u\0" for 2^32 - 1 */ 542 543 xe_gt_assert(gt, IS_SRIOV_PF(xe)); 544 xe_gt_assert(gt, root->d_inode->i_private == gt); 545 546 /* 547 * /sys/kernel/debug/dri/0/ 548 * ├── gt0 549 * │   ├── pf 550 */ 551 pfdentry = debugfs_create_dir("pf", root); 552 if (IS_ERR(pfdentry)) 553 return; 554 pfdentry->d_inode->i_private = gt; 555 556 drm_debugfs_create_files(pf_info, ARRAY_SIZE(pf_info), pfdentry, minor); 557 if (!xe_gt_is_media_type(gt)) { 558 drm_debugfs_create_files(pf_ggtt_info, 559 ARRAY_SIZE(pf_ggtt_info), 560 pfdentry, minor); 561 if (IS_DGFX(gt_to_xe(gt))) 562 drm_debugfs_create_files(pf_lmem_info, 563 ARRAY_SIZE(pf_lmem_info), 564 pfdentry, minor); 565 } 566 567 pf_add_policy_attrs(gt, pfdentry); 568 pf_add_config_attrs(gt, pfdentry, PFID); 569 570 for (n = 1; n <= totalvfs; n++) { 571 /* 572 * /sys/kernel/debug/dri/0/ 573 * ├── gt0 574 * │   ├── vf1 575 * │   ├── vf2 576 */ 577 snprintf(buf, sizeof(buf), "vf%u", n); 578 vfdentry = debugfs_create_dir(buf, root); 579 if (IS_ERR(vfdentry)) 580 break; 581 vfdentry->d_inode->i_private = (void *)(uintptr_t)n; 582 583 pf_add_config_attrs(gt, vfdentry, VFID(n)); 584 debugfs_create_file("control", 0600, vfdentry, NULL, &control_ops); 585 586 /* for testing/debugging purposes only! */ 587 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { 588 debugfs_create_file("guc_state", 589 IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV) ? 0600 : 0400, 590 vfdentry, NULL, &guc_state_ops); 591 debugfs_create_file("config_blob", 592 IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV) ? 0600 : 0400, 593 vfdentry, NULL, &config_blob_ops); 594 } 595 } 596}