File: igt_sriov_device.c

package info (click to toggle)
intel-gpu-tools 2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 62,024 kB
  • sloc: xml: 769,439; ansic: 348,692; python: 8,307; yacc: 2,781; perl: 1,196; sh: 1,178; lex: 487; asm: 227; makefile: 27; lisp: 11
file content (492 lines) | stat: -rw-r--r-- 11,616 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
// SPDX-License-Identifier: MIT
/*
 * Copyright(c) 2023 Intel Corporation. All rights reserved.
 */

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pciaccess.h>

#include "drmtest.h"
#include "igt_core.h"
#include "igt_device.h"
#include "igt_sriov_device.h"
#include "igt_sysfs.h"
#include "intel_io.h"
#include "xe/xe_query.h"

/**
 * igt_sriov_is_pf - Check if device is PF
 * @device: device file descriptor
 *
 * Determines if a device is a Physical Function (PF) by verifying
 * the presence of the sriov_totalvfs attribute and ensuring its
 * read value is greater than zero.
 *
 * Return:
 * True if device is PF, false otherwise.
 */
bool igt_sriov_is_pf(int device)
{
	uint32_t value = 0;
	int sysfs;

	sysfs = igt_sysfs_open(device);
	igt_assert_fd(sysfs);

	__igt_sysfs_get_u32(sysfs, "device/sriov_totalvfs", &value);
	close(sysfs);

	return value > 0;
}

static bool __pf_attr_get_u32(int pf, const char *attr, uint32_t *value)
{
	int sysfs;
	bool ret;

	igt_assert(igt_sriov_is_pf(pf));

	sysfs = igt_sysfs_open(pf);
	igt_assert_fd(sysfs);

	ret = __igt_sysfs_get_u32(sysfs, attr, value);
	close(sysfs);

	return ret;
}

static uint32_t pf_attr_get_u32(int pf, const char *attr)
{
	uint32_t value;

	igt_assert_f(__pf_attr_get_u32(pf, attr, &value),
		     "Failed to read %s attribute (%s)\n", attr, strerror(errno));

	return value;
}

static bool __pf_attr_set_u32(int pf, const char *attr, uint32_t value)
{
	int sysfs;
	bool ret;

	igt_assert(igt_sriov_is_pf(pf));

	sysfs = igt_sysfs_open(pf);
	igt_assert_fd(sysfs);

	ret = __igt_sysfs_set_u32(sysfs, attr, value);
	close(sysfs);

	return ret;
}

static void pf_attr_set_u32(int pf, const char *attr, uint32_t value)
{
	igt_assert_f(__pf_attr_set_u32(pf, attr, value),
		     "Failed to write %u to %s attribute (%s)\n", value, attr, strerror(errno));
}

/**
 * igt_sriov_vfs_supported - Check if VFs are supported
 * @pf: PF device file descriptor
 *
 * Determine VFs support by checking if value of sriov_totalvfs attribute
 * corresponding to @pf device is bigger than 0.
 *
 * Return:
 * True if VFs are supported, false otherwise.
 */
bool igt_sriov_vfs_supported(int pf)
{
	uint32_t totalvfs;

	if (!__pf_attr_get_u32(pf, "device/sriov_totalvfs", &totalvfs))
		return false;

	return totalvfs > 0;
}

/**
 * igt_sriov_get_totalvfs - Get maximum number of VFs that can be enabled
 * @pf: PF device file descriptor
 *
 * Maximum number of VFs that can be enabled is checked by reading
 * sriov_totalvfs attribute corresponding to @pf device.
 *
 * It asserts on failure.
 *
 * Return:
 * Maximum number of VFs that can be associated with given PF.
 */
unsigned int igt_sriov_get_total_vfs(int pf)
{
	return pf_attr_get_u32(pf, "device/sriov_totalvfs");
}

/**
 * igt_sriov_get_numvfs - Get number of enabled VFs
 * @pf: PF device file descriptor
 *
 * Number of enabled VFs is checked by reading sriov_numvfs attribute
 * corresponding to @pf device.
 *
 * It asserts on failure.
 *
 * Return:
 * Number of VFs enabled by given PF.
 */
unsigned int igt_sriov_get_enabled_vfs(int pf)
{
	return pf_attr_get_u32(pf, "device/sriov_numvfs");
}

/**
 * igt_sriov_enable_vfs - Enable VFs
 * @pf: PF device file descriptor
 * @num_vfs: Number of virtual functions to be enabled
 *
 * Enable VFs by writing @num_vfs to sriov_numvfs attribute corresponding to
 * @pf device.
 * It asserts on failure.
 */
void igt_sriov_enable_vfs(int pf, unsigned int num_vfs)
{
	igt_assert(num_vfs > 0);

	igt_debug("Enabling %u VFs\n", num_vfs);
	pf_attr_set_u32(pf, "device/sriov_numvfs", num_vfs);
}

/**
 * igt_sriov_disable_vfs - Disable VFs
 * @pf: PF device file descriptor
 *
 * Disable VFs by writing 0 to sriov_numvfs attribute corresponding to @pf
 * device.
 * It asserts on failure.
 */
void igt_sriov_disable_vfs(int pf)
{
	pf_attr_set_u32(pf, "device/sriov_numvfs", 0);
}

/**
 * igt_sriov_is_driver_autoprobe_enabled - Get VF driver autoprobe setting
 * @pf: PF device file descriptor
 *
 * Get current VF driver autoprobe setting by reading sriov_drivers_autoprobe
 * attribute corresponding to @pf device.
 *
 * It asserts on failure.
 *
 * Return:
 * True if autoprobe is enabled, false otherwise.
 */
bool igt_sriov_is_driver_autoprobe_enabled(int pf)
{
	return pf_attr_get_u32(pf, "device/sriov_drivers_autoprobe");
}

/**
 * igt_sriov_enable_driver_autoprobe - Enable VF driver autoprobe
 * @pf: PF device file descriptor
 *
 * Enable VF driver autoprobe setting by writing 1 to sriov_drivers_autoprobe
 * attribute corresponding to @pf device.
 *
 * If successful, kernel will automatically bind VFs to a compatible driver
 * immediately after they are enabled.
 * It asserts on failure.
 */
void igt_sriov_enable_driver_autoprobe(int pf)
{
	pf_attr_set_u32(pf,  "device/sriov_drivers_autoprobe", true);
}

/**
 * igt_sriov_disable_driver_autoprobe - Disable VF driver autoprobe
 * @pf: PF device file descriptor
 *
 * Disable VF driver autoprobe setting by writing 0 to sriov_drivers_autoprobe
 * attribute corresponding to @pf device.
 *
 * During VFs enabling driver won't be bound to VFs.
 * It asserts on failure.
 */
void igt_sriov_disable_driver_autoprobe(int pf)
{
	pf_attr_set_u32(pf,  "device/sriov_drivers_autoprobe", false);
}

/**
 * igt_sriov_open_vf_drm_device - Open VF DRM device node
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF)
 *
 * Open DRM device node for given VF.
 *
 * Return:
 * VF file descriptor or -1 on error.
 */
int igt_sriov_open_vf_drm_device(int pf, unsigned int vf_num)
{
	char dir_path[PATH_MAX], path[256], dev_name[16];
	DIR *dir;
	struct dirent *de;
	bool found = false;
	int fd;

	if (!vf_num)
		return -1;

	if (!igt_sysfs_path(pf, path, sizeof(path)))
		return -1;
	/* vf_num is 1-based, but virtfn is 0-based */
	snprintf(dir_path, sizeof(dir_path), "%s/device/virtfn%u/drm", path, vf_num - 1);

	dir = opendir(dir_path);
	if (!dir)
		return -1;
	while ((de = readdir(dir))) {
		unsigned int card_num;

		if (sscanf(de->d_name, "card%d", &card_num) == 1) {
			snprintf(dev_name, sizeof(dev_name), "/dev/dri/card%u", card_num);
			found = true;
			break;
		}
	}
	closedir(dir);

	if (!found)
		return -1;

	fd = __drm_open_device(dev_name, DRIVER_ANY);
	if (fd >= 0 && is_xe_device(fd))
		xe_device_get(fd);

	return fd;
}

/**
 * igt_sriov_is_vf_drm_driver_probed - Check if VF DRM driver is probed
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF)
 *
 * Verify if DRM driver is bound to VF device. Probe check is based on
 * existence of the DRM subsystem attribute in sysfs.
 *
 * Returns:
 * True if VF has DRM driver loaded, false if not.
 */
bool igt_sriov_is_vf_drm_driver_probed(int pf, unsigned int vf_num)
{
	char path[PATH_MAX];
	int sysfs;
	bool ret;

	igt_assert(vf_num > 0);

	sysfs = igt_sysfs_open(pf);
	igt_assert_fd(sysfs);
	/* vf_num is 1-based, but virtfn is 0-based */
	snprintf(path, sizeof(path), "device/virtfn%u/drm", vf_num - 1);
	ret = igt_sysfs_has_attr(sysfs, path);
	close(sysfs);

	return ret;
}

/*
 * __igt_sriov_get_vf_pci_slot_alloc:
 * @pf_sysfs: sysfs directory file descriptor
 * @vf_num: VF number (1-based)
 *
 * Resolve symbolic link from virtfnX to obtain the PCI slot address.
 * Returns a dynamically allocated string containing the PCI slot address,
 * or NULL if the link cannot be resolved.
 * The caller is responsible for freeing the returned memory.
 */
static char *__igt_sriov_get_vf_pci_slot_alloc(int pf_sysfs, unsigned int vf_num)
{
	char dir_path[PATH_MAX];
	char path[PATH_MAX];
	char *pci_slot_addr;
	int len;

	/* Adjust for 0-based index as vf_num is 1-based */
	if (vf_num)
		snprintf(dir_path, sizeof(dir_path), "device/virtfn%u",
			 vf_num - 1);
	else
		snprintf(dir_path, sizeof(dir_path), "device");

	len = readlinkat(pf_sysfs, dir_path, path, sizeof(path));
	if (len <= 0)
		return NULL;

	path[len] = '\0';
	pci_slot_addr = strrchr(path, '/') + 1;

	return pci_slot_addr ? strdup(pci_slot_addr) : NULL;
}

static bool __igt_sriov_bind_vf_drm_driver(int pf, unsigned int vf_num, bool bind)
{
	char *pci_slot;
	int sysfs;
	bool ret;

	igt_assert(vf_num > 0);

	sysfs = igt_sysfs_open(pf);
	igt_assert_fd(sysfs);

	pci_slot = __igt_sriov_get_vf_pci_slot_alloc(sysfs, vf_num);
	igt_assert(pci_slot);

	igt_debug("vf_num: %u, pci_slot: %s\n", vf_num, pci_slot);
	ret = igt_sysfs_set(sysfs, bind ? "device/driver/bind" : "device/driver/unbind", pci_slot);

	free(pci_slot);
	close(sysfs);

	return ret;
}

/**
 * igt_sriov_bind_vf_drm_driver - Bind DRM driver to VF
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF)
 *
 * Bind the DRM driver to given VF.
 * It asserts on failure.
 */
void igt_sriov_bind_vf_drm_driver(int pf, unsigned int vf_num)
{
	igt_assert(__igt_sriov_bind_vf_drm_driver(pf, vf_num, true));
}

/**
 * igt_sriov_unbind_vf_drm_driver - Unbind DRM driver from VF
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF)
 *
 * Unbind the DRM driver from given VF.
 * It asserts on failure.
 */
void igt_sriov_unbind_vf_drm_driver(int pf, unsigned int vf_num)
{
	igt_assert(__igt_sriov_bind_vf_drm_driver(pf, vf_num, false));
}

/**
 * igt_sriov_device_sysfs_open:
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF) or 0 for PF
 *
 * Open the sysfs directory corresponding to SR-IOV device.
 *
 * Returns:
 * The SR-IOV device sysfs directory fd, -1 on failure.
 */
int igt_sriov_device_sysfs_open(int pf, unsigned int vf_num)
{
	char path[PATH_MAX];
	int sysfs, fd;

	sysfs = igt_sysfs_open(pf);
	if (sysfs < 0)
		return -1;

	if (!vf_num)
		snprintf(path, sizeof(path), "device");
	else
		/* vf_num is 1-based, but virtfn is 0-based */
		snprintf(path, sizeof(path), "device/virtfn%u", vf_num - 1);

	fd = openat(sysfs, path, O_DIRECTORY | O_RDONLY);
	close(sysfs);

	return fd;
}

/**
 * igt_sriov_device_reset_exists:
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF) or 0 for PF
 *
 * Check if reset attribute exists for a given SR-IOV device.
 *
 * Returns:
 * True if reset attribute exists, false otherwise.
 */
bool igt_sriov_device_reset_exists(int pf, unsigned int vf_num)
{
	int sysfs;
	bool reset_exists;

	sysfs = igt_sriov_device_sysfs_open(pf, vf_num);
	if (sysfs < 0)
		return false;

	reset_exists = igt_sysfs_has_attr(sysfs, "reset");
	close(sysfs);

	return reset_exists;
}

/**
 * igt_sriov_device_reset:
 * @pf: PF device file descriptor
 * @vf_num: VF number (1-based to identify single VF) or 0 for PF
 *
 * Trigger FLR on a given VF.
 *
 * Returns:
 * True on success, false on failure.
 */
bool igt_sriov_device_reset(int pf, unsigned int vf_num)
{
	int sysfs;
	bool ret;

	sysfs = igt_sriov_device_sysfs_open(pf, vf_num);
	if (sysfs < 0)
		return false;

	igt_debug("Initiating FLR on VF%d\n", vf_num);
	ret = igt_sysfs_set(sysfs, "reset", "1");
	close(sysfs);

	return ret;
}

/**
 * intel_is_vf_device - Check if device is VF
 * @device: device file descriptor
 *
 * Determines if a device is a Virtual Function (VF)
 * by reading VF_CAPABILITY_REGISTER. If the least
 * significant bit is set the device is VF.
 *
 * Return:
 * True if device is VF, false otherwise.
 */
bool intel_is_vf_device(int fd)
{
#define VF_CAP_REG		0x1901f8
	struct intel_mmio_data mmio_data;
	uint32_t value;

	intel_register_access_init(&mmio_data, igt_device_get_pci_device(fd), false);
	value = intel_register_read(&mmio_data, VF_CAP_REG);
	intel_register_access_fini(&mmio_data);
	igt_require((value & ~1) == 0);

	return (value & 1) != 0;
}