1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include "xe_assert.h" 7 #include "xe_device.h" 8 #include "xe_gt_sriov_pf_config.h" 9 #include "xe_gt_sriov_pf_policy.h" 10 #include "xe_lmtt.h" 11 #include "xe_sriov.h" 12 #include "xe_sriov_pf_helpers.h" 13 #include "xe_sriov_pf_provision.h" 14 #include "xe_sriov_pf_provision_types.h" 15 #include "xe_sriov_printk.h" 16 17 static const char *mode_to_string(enum xe_sriov_provisioning_mode mode) 18 { 19 switch (mode) { 20 case XE_SRIOV_PROVISIONING_MODE_AUTO: 21 return "auto"; 22 case XE_SRIOV_PROVISIONING_MODE_CUSTOM: 23 return "custom"; 24 default: 25 return "<invalid>"; 26 } 27 } 28 29 static bool pf_auto_provisioning_mode(struct xe_device *xe) 30 { 31 xe_assert(xe, IS_SRIOV_PF(xe)); 32 33 return xe->sriov.pf.provision.mode == XE_SRIOV_PROVISIONING_MODE_AUTO; 34 } 35 36 static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs) 37 { 38 struct xe_gt *gt; 39 unsigned int id; 40 int result = 0; 41 int err; 42 43 for_each_gt(gt, xe, id) { 44 err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs); 45 result = result ?: err; 46 } 47 48 return result; 49 } 50 51 static void pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs) 52 { 53 struct xe_gt *gt; 54 unsigned int id; 55 unsigned int n; 56 57 for_each_gt(gt, xe, id) 58 for (n = 1; n <= num_vfs; n++) 59 xe_gt_sriov_pf_config_release(gt, n, true); 60 } 61 62 static void pf_unprovision_all_vfs(struct xe_device *xe) 63 { 64 pf_unprovision_vfs(xe, xe_sriov_pf_get_totalvfs(xe)); 65 } 66 67 /** 68 * xe_sriov_pf_provision_vfs() - Provision VFs in auto-mode. 69 * @xe: the PF &xe_device 70 * @num_vfs: the number of VFs to auto-provision 71 * 72 * This function can only be called on PF. 73 * 74 * Return: 0 on success or a negative error code on failure. 75 */ 76 int xe_sriov_pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs) 77 { 78 xe_assert(xe, IS_SRIOV_PF(xe)); 79 80 if (!pf_auto_provisioning_mode(xe)) 81 return 0; 82 83 return pf_provision_vfs(xe, num_vfs); 84 } 85 86 /** 87 * xe_sriov_pf_unprovision_vfs() - Unprovision VFs in auto-mode. 88 * @xe: the PF &xe_device 89 * @num_vfs: the number of VFs to unprovision 90 * 91 * This function can only be called on PF. 92 * 93 * Return: 0 on success or a negative error code on failure. 94 */ 95 int xe_sriov_pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs) 96 { 97 xe_assert(xe, IS_SRIOV_PF(xe)); 98 99 if (!pf_auto_provisioning_mode(xe)) 100 return 0; 101 102 pf_unprovision_vfs(xe, num_vfs); 103 return 0; 104 } 105 106 /** 107 * xe_sriov_pf_provision_set_mode() - Change VFs provision mode. 108 * @xe: the PF &xe_device 109 * @mode: the new VFs provisioning mode 110 * 111 * When changing from AUTO to CUSTOM mode, any already allocated VFs resources 112 * will remain allocated and will not be released upon VFs disabling. 113 * 114 * When changing back to AUTO mode, if VFs are not enabled, already allocated 115 * VFs resources will be immediately released. If VFs are still enabled, such 116 * mode change is rejected. 117 * 118 * This function can only be called on PF. 119 * 120 * Return: 0 on success or a negative error code on failure. 121 */ 122 int xe_sriov_pf_provision_set_mode(struct xe_device *xe, enum xe_sriov_provisioning_mode mode) 123 { 124 xe_assert(xe, IS_SRIOV_PF(xe)); 125 126 if (mode == xe->sriov.pf.provision.mode) 127 return 0; 128 129 if (mode == XE_SRIOV_PROVISIONING_MODE_AUTO) { 130 if (xe_sriov_pf_num_vfs(xe)) { 131 xe_sriov_dbg(xe, "can't restore %s: VFs must be disabled!\n", 132 mode_to_string(mode)); 133 return -EBUSY; 134 } 135 pf_unprovision_all_vfs(xe); 136 } 137 138 xe_sriov_dbg(xe, "mode %s changed to %s by %ps\n", 139 mode_to_string(xe->sriov.pf.provision.mode), 140 mode_to_string(mode), __builtin_return_address(0)); 141 xe->sriov.pf.provision.mode = mode; 142 return 0; 143 } 144 145 /** 146 * xe_sriov_pf_provision_bulk_apply_eq() - Change execution quantum for all VFs and PF. 147 * @xe: the PF &xe_device 148 * @eq: execution quantum in [ms] to set 149 * 150 * Change execution quantum (EQ) provisioning on all tiles/GTs. 151 * 152 * This function can only be called on PF. 153 * 154 * Return: 0 on success or a negative error code on failure. 155 */ 156 int xe_sriov_pf_provision_bulk_apply_eq(struct xe_device *xe, u32 eq) 157 { 158 struct xe_gt *gt; 159 unsigned int id; 160 int result = 0; 161 int err; 162 163 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 164 165 for_each_gt(gt, xe, id) { 166 err = xe_gt_sriov_pf_config_bulk_set_exec_quantum_locked(gt, eq); 167 result = result ?: err; 168 } 169 170 return result; 171 } 172 173 /** 174 * xe_sriov_pf_provision_apply_vf_eq() - Change VF's execution quantum. 175 * @xe: the PF &xe_device 176 * @vfid: the VF identifier 177 * @eq: execution quantum in [ms] to set 178 * 179 * Change VF's execution quantum (EQ) provisioning on all tiles/GTs. 180 * 181 * This function can only be called on PF. 182 * 183 * Return: 0 on success or a negative error code on failure. 184 */ 185 int xe_sriov_pf_provision_apply_vf_eq(struct xe_device *xe, unsigned int vfid, u32 eq) 186 { 187 struct xe_gt *gt; 188 unsigned int id; 189 int result = 0; 190 int err; 191 192 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 193 194 for_each_gt(gt, xe, id) { 195 err = xe_gt_sriov_pf_config_set_exec_quantum_locked(gt, vfid, eq); 196 result = result ?: err; 197 } 198 199 return result; 200 } 201 202 static int pf_report_unclean(struct xe_gt *gt, unsigned int vfid, 203 const char *what, u32 found, u32 expected) 204 { 205 char name[8]; 206 207 xe_sriov_dbg(gt_to_xe(gt), "%s on GT%u has %s=%u (expected %u)\n", 208 xe_sriov_function_name(vfid, name, sizeof(name)), 209 gt->info.id, what, found, expected); 210 return -EUCLEAN; 211 } 212 213 /** 214 * xe_sriov_pf_provision_query_vf_eq() - Query VF's execution quantum. 215 * @xe: the PF &xe_device 216 * @vfid: the VF identifier 217 * @eq: placeholder for the returned execution quantum in [ms] 218 * 219 * Query VF's execution quantum (EQ) provisioning from all tiles/GTs. 220 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned. 221 * 222 * This function can only be called on PF. 223 * 224 * Return: 0 on success or a negative error code on failure. 225 */ 226 int xe_sriov_pf_provision_query_vf_eq(struct xe_device *xe, unsigned int vfid, u32 *eq) 227 { 228 struct xe_gt *gt; 229 unsigned int id; 230 int count = 0; 231 u32 value; 232 233 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 234 235 for_each_gt(gt, xe, id) { 236 value = xe_gt_sriov_pf_config_get_exec_quantum_locked(gt, vfid); 237 if (!count++) 238 *eq = value; 239 else if (value != *eq) 240 return pf_report_unclean(gt, vfid, "EQ", value, *eq); 241 } 242 243 return !count ? -ENODATA : 0; 244 } 245 246 /** 247 * xe_sriov_pf_provision_bulk_apply_pt() - Change preemption timeout for all VFs and PF. 248 * @xe: the PF &xe_device 249 * @pt: preemption timeout in [us] to set 250 * 251 * Change preemption timeout (PT) provisioning on all tiles/GTs. 252 * 253 * This function can only be called on PF. 254 * 255 * Return: 0 on success or a negative error code on failure. 256 */ 257 int xe_sriov_pf_provision_bulk_apply_pt(struct xe_device *xe, u32 pt) 258 { 259 struct xe_gt *gt; 260 unsigned int id; 261 int result = 0; 262 int err; 263 264 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 265 266 for_each_gt(gt, xe, id) { 267 err = xe_gt_sriov_pf_config_bulk_set_preempt_timeout_locked(gt, pt); 268 result = result ?: err; 269 } 270 271 return result; 272 } 273 274 /** 275 * xe_sriov_pf_provision_apply_vf_pt() - Change VF's preemption timeout. 276 * @xe: the PF &xe_device 277 * @vfid: the VF identifier 278 * @pt: preemption timeout in [us] to set 279 * 280 * Change VF's preemption timeout (PT) provisioning on all tiles/GTs. 281 * 282 * This function can only be called on PF. 283 * 284 * Return: 0 on success or a negative error code on failure. 285 */ 286 int xe_sriov_pf_provision_apply_vf_pt(struct xe_device *xe, unsigned int vfid, u32 pt) 287 { 288 struct xe_gt *gt; 289 unsigned int id; 290 int result = 0; 291 int err; 292 293 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 294 295 for_each_gt(gt, xe, id) { 296 err = xe_gt_sriov_pf_config_set_preempt_timeout_locked(gt, vfid, pt); 297 result = result ?: err; 298 } 299 300 return result; 301 } 302 303 /** 304 * xe_sriov_pf_provision_query_vf_pt() - Query VF's preemption timeout. 305 * @xe: the PF &xe_device 306 * @vfid: the VF identifier 307 * @pt: placeholder for the returned preemption timeout in [us] 308 * 309 * Query VF's preemption timeout (PT) provisioning from all tiles/GTs. 310 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned. 311 * 312 * This function can only be called on PF. 313 * 314 * Return: 0 on success or a negative error code on failure. 315 */ 316 int xe_sriov_pf_provision_query_vf_pt(struct xe_device *xe, unsigned int vfid, u32 *pt) 317 { 318 struct xe_gt *gt; 319 unsigned int id; 320 int count = 0; 321 u32 value; 322 323 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 324 325 for_each_gt(gt, xe, id) { 326 value = xe_gt_sriov_pf_config_get_preempt_timeout_locked(gt, vfid); 327 if (!count++) 328 *pt = value; 329 else if (value != *pt) 330 return pf_report_unclean(gt, vfid, "PT", value, *pt); 331 } 332 333 return !count ? -ENODATA : 0; 334 } 335 336 /** 337 * xe_sriov_pf_provision_bulk_apply_priority() - Change scheduling priority of all VFs and PF. 338 * @xe: the PF &xe_device 339 * @prio: scheduling priority to set 340 * 341 * Change the scheduling priority provisioning on all tiles/GTs. 342 * 343 * This function can only be called on PF. 344 * 345 * Return: 0 on success or a negative error code on failure. 346 */ 347 int xe_sriov_pf_provision_bulk_apply_priority(struct xe_device *xe, u32 prio) 348 { 349 bool sched_if_idle; 350 struct xe_gt *gt; 351 unsigned int id; 352 int result = 0; 353 int err; 354 355 /* 356 * Currently, priority changes that involves VFs are only allowed using 357 * the 'sched_if_idle' policy KLV, so only LOW and NORMAL are supported. 358 */ 359 xe_assert(xe, prio < GUC_SCHED_PRIORITY_HIGH); 360 sched_if_idle = prio == GUC_SCHED_PRIORITY_NORMAL; 361 362 for_each_gt(gt, xe, id) { 363 err = xe_gt_sriov_pf_policy_set_sched_if_idle(gt, sched_if_idle); 364 result = result ?: err; 365 } 366 367 return result; 368 } 369 370 /** 371 * xe_sriov_pf_provision_apply_vf_priority() - Change VF's scheduling priority. 372 * @xe: the PF &xe_device 373 * @vfid: the VF identifier 374 * @prio: scheduling priority to set 375 * 376 * Change VF's scheduling priority provisioning on all tiles/GTs. 377 * 378 * This function can only be called on PF. 379 * 380 * Return: 0 on success or a negative error code on failure. 381 */ 382 int xe_sriov_pf_provision_apply_vf_priority(struct xe_device *xe, unsigned int vfid, u32 prio) 383 { 384 struct xe_gt *gt; 385 unsigned int id; 386 int result = 0; 387 int err; 388 389 for_each_gt(gt, xe, id) { 390 err = xe_gt_sriov_pf_config_set_sched_priority(gt, vfid, prio); 391 result = result ?: err; 392 } 393 394 return result; 395 } 396 397 /** 398 * xe_sriov_pf_provision_query_vf_priority() - Query VF's scheduling priority. 399 * @xe: the PF &xe_device 400 * @vfid: the VF identifier 401 * @prio: placeholder for the returned scheduling priority 402 * 403 * Query VF's scheduling priority provisioning from all tiles/GTs. 404 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned. 405 * 406 * This function can only be called on PF. 407 * 408 * Return: 0 on success or a negative error code on failure. 409 */ 410 int xe_sriov_pf_provision_query_vf_priority(struct xe_device *xe, unsigned int vfid, u32 *prio) 411 { 412 struct xe_gt *gt; 413 unsigned int id; 414 int count = 0; 415 u32 value; 416 417 for_each_gt(gt, xe, id) { 418 value = xe_gt_sriov_pf_config_get_sched_priority(gt, vfid); 419 if (!count++) 420 *prio = value; 421 else if (value != *prio) 422 return pf_report_unclean(gt, vfid, "priority", value, *prio); 423 } 424 425 return !count ? -ENODATA : 0; 426 } 427 428 static u64 vram_per_tile(struct xe_tile *tile, u64 total) 429 { 430 struct xe_device *xe = tile->xe; 431 unsigned int tcount = xe->info.tile_count; 432 u64 alignment = xe_lmtt_page_size(&tile->sriov.pf.lmtt); 433 434 total = round_up(total, tcount * alignment); 435 return div_u64(total, tcount); 436 } 437 438 /** 439 * xe_sriov_pf_provision_bulk_apply_vram() - Change VRAM provisioning for all VFs. 440 * @xe: the PF &xe_device 441 * @size: the VRAM size in [bytes] to set 442 * 443 * Change all VFs VRAM (LMEM) provisioning on all tiles. 444 * 445 * This function can only be called on PF. 446 * 447 * Return: 0 on success or a negative error code on failure. 448 */ 449 int xe_sriov_pf_provision_bulk_apply_vram(struct xe_device *xe, u64 size) 450 { 451 unsigned int num_vfs = xe_sriov_pf_get_totalvfs(xe); 452 struct xe_tile *tile; 453 unsigned int id; 454 int result = 0; 455 int err; 456 457 xe_assert(xe, xe_device_has_lmtt(xe)); 458 459 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 460 461 for_each_tile(tile, xe, id) { 462 err = xe_gt_sriov_pf_config_bulk_set_lmem_locked(tile->primary_gt, 463 VFID(1), num_vfs, 464 vram_per_tile(tile, size)); 465 result = result ?: err; 466 } 467 468 return result; 469 } 470 471 /** 472 * xe_sriov_pf_provision_apply_vf_vram() - Change single VF VRAM allocation. 473 * @xe: the PF &xe_device 474 * @vfid: the VF identifier (can't be 0 == PFID) 475 * @size: VRAM size to set 476 * 477 * Change VF's VRAM provisioning on all tiles/GTs. 478 * 479 * This function can only be called on PF. 480 * 481 * Return: 0 on success or a negative error code on failure. 482 */ 483 int xe_sriov_pf_provision_apply_vf_vram(struct xe_device *xe, unsigned int vfid, u64 size) 484 { 485 struct xe_tile *tile; 486 unsigned int id; 487 int result = 0; 488 int err; 489 490 xe_assert(xe, vfid); 491 xe_assert(xe, xe_device_has_lmtt(xe)); 492 493 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 494 495 for_each_tile(tile, xe, id) { 496 err = xe_gt_sriov_pf_config_set_lmem_locked(tile->primary_gt, vfid, 497 vram_per_tile(tile, size)); 498 result = result ?: err; 499 } 500 501 return result; 502 } 503 504 /** 505 * xe_sriov_pf_provision_query_vf_vram() - Query VF's VRAM allocation. 506 * @xe: the PF &xe_device 507 * @vfid: the VF identifier (can't be 0 == PFID) 508 * @size: placeholder for the returned VRAM size 509 * 510 * Query VF's VRAM provisioning from all tiles/GTs. 511 * 512 * This function can only be called on PF. 513 * 514 * Return: 0 on success or a negative error code on failure. 515 */ 516 int xe_sriov_pf_provision_query_vf_vram(struct xe_device *xe, unsigned int vfid, u64 *size) 517 { 518 struct xe_tile *tile; 519 unsigned int id; 520 u64 total = 0; 521 522 xe_assert(xe, vfid); 523 524 guard(mutex)(xe_sriov_pf_master_mutex(xe)); 525 526 for_each_tile(tile, xe, id) 527 total += xe_gt_sriov_pf_config_get_lmem_locked(tile->primary_gt, vfid); 528 529 *size = total; 530 return 0; 531 } 532