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;
}
|