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