Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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_sriov.h"
11#include "xe_sriov_pf_helpers.h"
12#include "xe_sriov_pf_provision.h"
13#include "xe_sriov_pf_provision_types.h"
14#include "xe_sriov_printk.h"
15
16static const char *mode_to_string(enum xe_sriov_provisioning_mode mode)
17{
18 switch (mode) {
19 case XE_SRIOV_PROVISIONING_MODE_AUTO:
20 return "auto";
21 case XE_SRIOV_PROVISIONING_MODE_CUSTOM:
22 return "custom";
23 default:
24 return "<invalid>";
25 }
26}
27
28static bool pf_auto_provisioning_mode(struct xe_device *xe)
29{
30 xe_assert(xe, IS_SRIOV_PF(xe));
31
32 return xe->sriov.pf.provision.mode == XE_SRIOV_PROVISIONING_MODE_AUTO;
33}
34
35static bool pf_needs_provisioning(struct xe_gt *gt, unsigned int num_vfs)
36{
37 unsigned int n;
38
39 for (n = 1; n <= num_vfs; n++)
40 if (!xe_gt_sriov_pf_config_is_empty(gt, n))
41 return false;
42
43 return true;
44}
45
46static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs)
47{
48 struct xe_gt *gt;
49 unsigned int id;
50 int result = 0;
51 int err;
52
53 for_each_gt(gt, xe, id) {
54 if (!pf_needs_provisioning(gt, num_vfs))
55 return -EUCLEAN;
56 err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs);
57 result = result ?: err;
58 }
59
60 return result;
61}
62
63static void pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs)
64{
65 struct xe_gt *gt;
66 unsigned int id;
67 unsigned int n;
68
69 for_each_gt(gt, xe, id)
70 for (n = 1; n <= num_vfs; n++)
71 xe_gt_sriov_pf_config_release(gt, n, true);
72}
73
74static void pf_unprovision_all_vfs(struct xe_device *xe)
75{
76 pf_unprovision_vfs(xe, xe_sriov_pf_get_totalvfs(xe));
77}
78
79/**
80 * xe_sriov_pf_provision_vfs() - Provision VFs in auto-mode.
81 * @xe: the PF &xe_device
82 * @num_vfs: the number of VFs to auto-provision
83 *
84 * This function can only be called on PF.
85 *
86 * Return: 0 on success or a negative error code on failure.
87 */
88int xe_sriov_pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs)
89{
90 xe_assert(xe, IS_SRIOV_PF(xe));
91
92 if (!pf_auto_provisioning_mode(xe))
93 return 0;
94
95 return pf_provision_vfs(xe, num_vfs);
96}
97
98/**
99 * xe_sriov_pf_unprovision_vfs() - Unprovision VFs in auto-mode.
100 * @xe: the PF &xe_device
101 * @num_vfs: the number of VFs to unprovision
102 *
103 * This function can only be called on PF.
104 *
105 * Return: 0 on success or a negative error code on failure.
106 */
107int xe_sriov_pf_unprovision_vfs(struct xe_device *xe, unsigned int num_vfs)
108{
109 xe_assert(xe, IS_SRIOV_PF(xe));
110
111 if (!pf_auto_provisioning_mode(xe))
112 return 0;
113
114 pf_unprovision_vfs(xe, num_vfs);
115 return 0;
116}
117
118/**
119 * xe_sriov_pf_provision_set_mode() - Change VFs provision mode.
120 * @xe: the PF &xe_device
121 * @mode: the new VFs provisioning mode
122 *
123 * When changing from AUTO to CUSTOM mode, any already allocated VFs resources
124 * will remain allocated and will not be released upon VFs disabling.
125 *
126 * When changing back to AUTO mode, if VFs are not enabled, already allocated
127 * VFs resources will be immediately released. If VFs are still enabled, such
128 * mode change is rejected.
129 *
130 * This function can only be called on PF.
131 *
132 * Return: 0 on success or a negative error code on failure.
133 */
134int xe_sriov_pf_provision_set_mode(struct xe_device *xe, enum xe_sriov_provisioning_mode mode)
135{
136 xe_assert(xe, IS_SRIOV_PF(xe));
137
138 if (mode == xe->sriov.pf.provision.mode)
139 return 0;
140
141 if (mode == XE_SRIOV_PROVISIONING_MODE_AUTO) {
142 if (xe_sriov_pf_num_vfs(xe)) {
143 xe_sriov_dbg(xe, "can't restore %s: VFs must be disabled!\n",
144 mode_to_string(mode));
145 return -EBUSY;
146 }
147 pf_unprovision_all_vfs(xe);
148 }
149
150 xe_sriov_dbg(xe, "mode %s changed to %s by %ps\n",
151 mode_to_string(xe->sriov.pf.provision.mode),
152 mode_to_string(mode), __builtin_return_address(0));
153 xe->sriov.pf.provision.mode = mode;
154 return 0;
155}
156
157/**
158 * xe_sriov_pf_provision_bulk_apply_eq() - Change execution quantum for all VFs and PF.
159 * @xe: the PF &xe_device
160 * @eq: execution quantum in [ms] to set
161 *
162 * Change execution quantum (EQ) provisioning on all tiles/GTs.
163 *
164 * This function can only be called on PF.
165 *
166 * Return: 0 on success or a negative error code on failure.
167 */
168int xe_sriov_pf_provision_bulk_apply_eq(struct xe_device *xe, u32 eq)
169{
170 struct xe_gt *gt;
171 unsigned int id;
172 int result = 0;
173 int err;
174
175 guard(mutex)(xe_sriov_pf_master_mutex(xe));
176
177 for_each_gt(gt, xe, id) {
178 err = xe_gt_sriov_pf_config_bulk_set_exec_quantum_locked(gt, eq);
179 result = result ?: err;
180 }
181
182 return result;
183}
184
185/**
186 * xe_sriov_pf_provision_apply_vf_eq() - Change VF's execution quantum.
187 * @xe: the PF &xe_device
188 * @vfid: the VF identifier
189 * @eq: execution quantum in [ms] to set
190 *
191 * Change VF's 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 */
197int xe_sriov_pf_provision_apply_vf_eq(struct xe_device *xe, unsigned int vfid, 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_set_exec_quantum_locked(gt, vfid, eq);
208 result = result ?: err;
209 }
210
211 return result;
212}
213
214static int pf_report_unclean(struct xe_gt *gt, unsigned int vfid,
215 const char *what, u32 found, u32 expected)
216{
217 char name[8];
218
219 xe_sriov_dbg(gt_to_xe(gt), "%s on GT%u has %s=%u (expected %u)\n",
220 xe_sriov_function_name(vfid, name, sizeof(name)),
221 gt->info.id, what, found, expected);
222 return -EUCLEAN;
223}
224
225/**
226 * xe_sriov_pf_provision_query_vf_eq() - Query VF's execution quantum.
227 * @xe: the PF &xe_device
228 * @vfid: the VF identifier
229 * @eq: placeholder for the returned execution quantum in [ms]
230 *
231 * Query VF's execution quantum (EQ) provisioning from all tiles/GTs.
232 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned.
233 *
234 * This function can only be called on PF.
235 *
236 * Return: 0 on success or a negative error code on failure.
237 */
238int xe_sriov_pf_provision_query_vf_eq(struct xe_device *xe, unsigned int vfid, u32 *eq)
239{
240 struct xe_gt *gt;
241 unsigned int id;
242 int count = 0;
243 u32 value;
244
245 guard(mutex)(xe_sriov_pf_master_mutex(xe));
246
247 for_each_gt(gt, xe, id) {
248 value = xe_gt_sriov_pf_config_get_exec_quantum_locked(gt, vfid);
249 if (!count++)
250 *eq = value;
251 else if (value != *eq)
252 return pf_report_unclean(gt, vfid, "EQ", value, *eq);
253 }
254
255 return !count ? -ENODATA : 0;
256}
257
258/**
259 * xe_sriov_pf_provision_bulk_apply_pt() - Change preemption timeout for all VFs and PF.
260 * @xe: the PF &xe_device
261 * @pt: preemption timeout in [us] to set
262 *
263 * Change preemption timeout (PT) provisioning on all tiles/GTs.
264 *
265 * This function can only be called on PF.
266 *
267 * Return: 0 on success or a negative error code on failure.
268 */
269int xe_sriov_pf_provision_bulk_apply_pt(struct xe_device *xe, u32 pt)
270{
271 struct xe_gt *gt;
272 unsigned int id;
273 int result = 0;
274 int err;
275
276 guard(mutex)(xe_sriov_pf_master_mutex(xe));
277
278 for_each_gt(gt, xe, id) {
279 err = xe_gt_sriov_pf_config_bulk_set_preempt_timeout_locked(gt, pt);
280 result = result ?: err;
281 }
282
283 return result;
284}
285
286/**
287 * xe_sriov_pf_provision_apply_vf_pt() - Change VF's preemption timeout.
288 * @xe: the PF &xe_device
289 * @vfid: the VF identifier
290 * @pt: preemption timeout in [us] to set
291 *
292 * Change VF's 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 */
298int xe_sriov_pf_provision_apply_vf_pt(struct xe_device *xe, unsigned int vfid, 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_set_preempt_timeout_locked(gt, vfid, pt);
309 result = result ?: err;
310 }
311
312 return result;
313}
314
315/**
316 * xe_sriov_pf_provision_query_vf_pt() - Query VF's preemption timeout.
317 * @xe: the PF &xe_device
318 * @vfid: the VF identifier
319 * @pt: placeholder for the returned preemption timeout in [us]
320 *
321 * Query VF's preemption timeout (PT) provisioning from all tiles/GTs.
322 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned.
323 *
324 * This function can only be called on PF.
325 *
326 * Return: 0 on success or a negative error code on failure.
327 */
328int xe_sriov_pf_provision_query_vf_pt(struct xe_device *xe, unsigned int vfid, u32 *pt)
329{
330 struct xe_gt *gt;
331 unsigned int id;
332 int count = 0;
333 u32 value;
334
335 guard(mutex)(xe_sriov_pf_master_mutex(xe));
336
337 for_each_gt(gt, xe, id) {
338 value = xe_gt_sriov_pf_config_get_preempt_timeout_locked(gt, vfid);
339 if (!count++)
340 *pt = value;
341 else if (value != *pt)
342 return pf_report_unclean(gt, vfid, "PT", value, *pt);
343 }
344
345 return !count ? -ENODATA : 0;
346}
347
348/**
349 * xe_sriov_pf_provision_bulk_apply_priority() - Change scheduling priority of all VFs and PF.
350 * @xe: the PF &xe_device
351 * @prio: scheduling priority to set
352 *
353 * Change the scheduling priority provisioning on all tiles/GTs.
354 *
355 * This function can only be called on PF.
356 *
357 * Return: 0 on success or a negative error code on failure.
358 */
359int xe_sriov_pf_provision_bulk_apply_priority(struct xe_device *xe, u32 prio)
360{
361 bool sched_if_idle;
362 struct xe_gt *gt;
363 unsigned int id;
364 int result = 0;
365 int err;
366
367 /*
368 * Currently, priority changes that involves VFs are only allowed using
369 * the 'sched_if_idle' policy KLV, so only LOW and NORMAL are supported.
370 */
371 xe_assert(xe, prio < GUC_SCHED_PRIORITY_HIGH);
372 sched_if_idle = prio == GUC_SCHED_PRIORITY_NORMAL;
373
374 for_each_gt(gt, xe, id) {
375 err = xe_gt_sriov_pf_policy_set_sched_if_idle(gt, sched_if_idle);
376 result = result ?: err;
377 }
378
379 return result;
380}
381
382/**
383 * xe_sriov_pf_provision_apply_vf_priority() - Change VF's scheduling priority.
384 * @xe: the PF &xe_device
385 * @vfid: the VF identifier
386 * @prio: scheduling priority to set
387 *
388 * Change VF's scheduling priority provisioning on all tiles/GTs.
389 *
390 * This function can only be called on PF.
391 *
392 * Return: 0 on success or a negative error code on failure.
393 */
394int xe_sriov_pf_provision_apply_vf_priority(struct xe_device *xe, unsigned int vfid, u32 prio)
395{
396 struct xe_gt *gt;
397 unsigned int id;
398 int result = 0;
399 int err;
400
401 for_each_gt(gt, xe, id) {
402 err = xe_gt_sriov_pf_config_set_sched_priority(gt, vfid, prio);
403 result = result ?: err;
404 }
405
406 return result;
407}
408
409/**
410 * xe_sriov_pf_provision_query_vf_priority() - Query VF's scheduling priority.
411 * @xe: the PF &xe_device
412 * @vfid: the VF identifier
413 * @prio: placeholder for the returned scheduling priority
414 *
415 * Query VF's scheduling priority provisioning from all tiles/GTs.
416 * If values across tiles/GTs are inconsistent then -EUCLEAN error will be returned.
417 *
418 * This function can only be called on PF.
419 *
420 * Return: 0 on success or a negative error code on failure.
421 */
422int xe_sriov_pf_provision_query_vf_priority(struct xe_device *xe, unsigned int vfid, u32 *prio)
423{
424 struct xe_gt *gt;
425 unsigned int id;
426 int count = 0;
427 u32 value;
428
429 for_each_gt(gt, xe, id) {
430 value = xe_gt_sriov_pf_config_get_sched_priority(gt, vfid);
431 if (!count++)
432 *prio = value;
433 else if (value != *prio)
434 return pf_report_unclean(gt, vfid, "priority", value, *prio);
435 }
436
437 return !count ? -ENODATA : 0;
438}