xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_provision.c (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
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