[PATCH 1/4] virpci: changed the work with PCI via libpciaccess

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



sysfs is used to get a list of PCI devices. It doesn't work under
FreeBSD. The libpciaccess library provides cross-platform functions
for accessing the PCI bus.

Signed-off-by: Alexander Shursha <kekek2@xxxxx>
---
 src/meson.build         |   1 +
 src/util/virpci.c       | 465 ++++++++++------------------------------
 tests/qemuhotplugtest.c |  11 +-
 tests/qemumemlocktest.c |   9 +
 tests/qemuxmlconftest.c |   9 +
 tests/virpcimock.c      |  22 +-
 6 files changed, 162 insertions(+), 355 deletions(-)

diff --git a/src/meson.build b/src/meson.build
index 9413192a55..39788ac4d7 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -411,6 +411,7 @@ libvirt_lib = shared_library(
   dtrace_gen_objects,
   dependencies: [
     src_dep,
+    pciaccess_dep
   ],
   link_args: libvirt_link_args,
   link_whole: [
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 90617e69c6..b5bbe73ece 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2,6 +2,7 @@
  * virpci.c: helper APIs for managing host PCI devices
  *
  * Copyright (C) 2009-2015 Red Hat, Inc.
+ * Copyright (C) 2024-2025 Future Crew, LLC
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <pciaccess.h>
 
 #ifdef __linux__
 # include <sys/utsname.h>
@@ -72,7 +74,7 @@ struct _virPCIDevice {
 
     char          *name;              /* domain:bus:slot.function */
     char          id[PCI_ID_LEN];     /* product vendor */
-    char          *path;
+    struct pci_device *device;
 
     /* The driver:domain which uses the device */
     char          *used_by_drvname;
@@ -359,121 +361,6 @@ virPCIDeviceGetCurrentDriverNameAndType(virPCIDevice *dev,
 }
 
 
-static int
-virPCIDeviceConfigOpenInternal(virPCIDevice *dev, bool readonly, bool fatal)
-{
-    int fd;
-
-    fd = open(dev->path, readonly ? O_RDONLY : O_RDWR);
-
-    if (fd < 0) {
-        if (fatal) {
-            virReportSystemError(errno,
-                                 _("Failed to open config space file '%1$s'"),
-                                 dev->path);
-        } else {
-            VIR_WARN("Failed to open config space file '%s': %s",
-                     dev->path, g_strerror(errno));
-        }
-        return -1;
-    }
-
-    VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path);
-    return fd;
-}
-
-static int
-virPCIDeviceConfigOpen(virPCIDevice *dev)
-{
-    return virPCIDeviceConfigOpenInternal(dev, true, true);
-}
-
-static int
-virPCIDeviceConfigOpenTry(virPCIDevice *dev)
-{
-    return virPCIDeviceConfigOpenInternal(dev, true, false);
-}
-
-static int
-virPCIDeviceConfigOpenWrite(virPCIDevice *dev)
-{
-    return virPCIDeviceConfigOpenInternal(dev, false, true);
-}
-
-static void
-virPCIDeviceConfigClose(virPCIDevice *dev, int cfgfd)
-{
-    if (VIR_CLOSE(cfgfd) < 0) {
-        VIR_WARN("Failed to close config space file '%s': %s",
-                 dev->path, g_strerror(errno));
-    }
-}
-
-
-static int
-virPCIDeviceRead(virPCIDevice *dev,
-                 int cfgfd,
-                 unsigned int pos,
-                 uint8_t *buf,
-                 unsigned int buflen)
-{
-    memset(buf, 0, buflen);
-    errno = 0;
-
-    if (lseek(cfgfd, pos, SEEK_SET) != pos ||
-        saferead(cfgfd, buf, buflen) != buflen) {
-        VIR_DEBUG("Failed to read %u bytes at %u from '%s' : %s",
-                 buflen, pos, dev->path, g_strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
-
-/**
- * virPCIDeviceReadN:
- * @dev: virPCIDevice object (used only to log name of config file)
- * @cfgfd: open file descriptor for device config file in sysfs
- * @pos: byte offset in the file to read from
- *
- * read "N" (where "N" is "8", "16", or "32", and appears at the end
- * of the function name) bytes from a PCI device's already-opened
- * sysfs config file and return them as the return value from the
- * function.
- *
- * Returns the value at @pos in the file, or 0 if there was an
- * error. NB: since 0 could be a valid value, occurrence of an error
- * must be determined by examining errno. errno is always reset to 0
- * before the seek/read is attempted (see virPCIDeviceRead()), so if
- * errno != 0 on return from one of these functions, then either the
- * seek or the read operation failed for some reason. If errno == 0
- * and the return value is 0, then the config file really does contain
- * the value 0 at @pos.
- */
-static uint8_t
-virPCIDeviceRead8(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
-    uint8_t buf;
-    virPCIDeviceRead(dev, cfgfd, pos, &buf, sizeof(buf));
-    return buf;
-}
-
-static uint16_t
-virPCIDeviceRead16(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
-    uint8_t buf[2];
-    virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
-    return (buf[0] << 0) | (buf[1] << 8);
-}
-
-static uint32_t
-virPCIDeviceRead32(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
-    uint8_t buf[4];
-    virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
-    return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
 static int
 virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
 {
@@ -499,36 +386,6 @@ virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
     return 0;
 }
 
-static int
-virPCIDeviceWrite(virPCIDevice *dev,
-                  int cfgfd,
-                  unsigned int pos,
-                  uint8_t *buf,
-                  unsigned int buflen)
-{
-    if (lseek(cfgfd, pos, SEEK_SET) != pos ||
-        safewrite(cfgfd, buf, buflen) != buflen) {
-        VIR_WARN("Failed to write to '%s' : %s", dev->path,
-                 g_strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
-static void
-virPCIDeviceWrite16(virPCIDevice *dev, int cfgfd, unsigned int pos, uint16_t val)
-{
-    uint8_t buf[2] = { (val >> 0), (val >> 8) };
-    virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
-}
-
-static void
-virPCIDeviceWrite32(virPCIDevice *dev, int cfgfd, unsigned int pos, uint32_t val)
-{
-    uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) };
-    virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
-}
-
 typedef int (*virPCIDeviceIterPredicate)(virPCIDevice *, virPCIDevice *,
                                          void *);
 
@@ -610,7 +467,6 @@ virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate,
  */
 static int
 virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
-                                 int cfgfd,
                                  unsigned int capability,
                                  unsigned int *offset)
 {
@@ -619,11 +475,13 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
 
     *offset = 0; /* assume failure (*nothing* can be at offset 0) */
 
-    status = virPCIDeviceRead16(dev, cfgfd, PCI_STATUS);
+    pci_device_cfg_read_u16(dev->device, &status, PCI_STATUS);
+
     if (errno != 0 || !(status & PCI_STATUS_CAP_LIST))
         goto error;
 
-    pos = virPCIDeviceRead8(dev, cfgfd, PCI_CAPABILITY_LIST);
+    pci_device_cfg_read_u8(dev->device, &pos, PCI_CAPABILITY_LIST);
+
     if (errno != 0)
         goto error;
 
@@ -635,7 +493,9 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
      * capabilities here.
      */
     while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
-        uint8_t capid = virPCIDeviceRead8(dev, cfgfd, pos);
+        uint8_t capid;
+        pci_device_cfg_read_u8(dev->device, &capid, pos);
+
         if (errno != 0)
             goto error;
 
@@ -646,7 +506,8 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
             return 0;
         }
 
-        pos = virPCIDeviceRead8(dev, cfgfd, pos + 1);
+        pci_device_cfg_read_u8(dev->device, &pos, pos + 1);
+
         if (errno != 0)
             goto error;
     }
@@ -665,7 +526,6 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
 
 static unsigned int
 virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
-                                         int cfgfd,
                                          unsigned int capability)
 {
     int ttl;
@@ -677,7 +537,7 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
     pos = PCI_EXT_CAP_BASE;
 
     while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) {
-        header = virPCIDeviceRead32(dev, cfgfd, pos);
+        header = pci_device_cfg_read_u32(dev->device, &header, pos);
 
         if ((header & PCI_EXT_CAP_ID_MASK) == capability)
             return pos;
@@ -693,7 +553,7 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
  * not have FLR, 1 if it does, and -1 on error
  */
 static bool
-virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev)
 {
     uint32_t caps;
     unsigned int pos;
@@ -707,7 +567,7 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
      * on SR-IOV NICs at the moment.
      */
     if (dev->pcie_cap_pos) {
-        caps = virPCIDeviceRead32(dev, cfgfd, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
+        pci_device_cfg_read_u32(dev->device, &caps, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
         if (caps & PCI_EXP_DEVCAP_FLR) {
             VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
             return true;
@@ -718,11 +578,13 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
      * the same thing, except for conventional PCI
      * devices. This is not common yet.
      */
-    if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_AF, &pos) < 0)
+    if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_AF, &pos) < 0)
         goto error;
 
     if (pos) {
-        caps = virPCIDeviceRead16(dev, cfgfd, pos + PCI_AF_CAP);
+        uint16_t caps16;
+        pci_device_cfg_read_u16(dev->device, &caps16, pos + PCI_AF_CAP);
+        caps = caps16;
         if (caps & PCI_AF_CAP_FLR) {
             VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
             return true;
@@ -754,13 +616,13 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
  * internal reset, not just a soft reset.
  */
 static bool
-virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev)
 {
     if (dev->pci_pm_cap_pos) {
         uint32_t ctl;
 
         /* require the NO_SOFT_RESET bit is clear */
-        ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+        pci_device_cfg_read_u32(dev->device, &ctl, dev->pci_pm_cap_pos + PCI_PM_CTRL);
         if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
             VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
             return true;
@@ -811,26 +673,22 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
     uint8_t header_type, secondary, subordinate;
     virPCIDevice **best = data;
     int ret = 0;
-    int fd;
 
     if (dev->address.domain != check->address.domain)
         return 0;
 
-    if ((fd = virPCIDeviceConfigOpenTry(check)) < 0)
-        return 0;
-
     /* Is it a bridge? */
     ret = virPCIDeviceReadClass(check, &device_class);
     if (ret < 0 || device_class != PCI_CLASS_BRIDGE_PCI)
-        goto cleanup;
+        return ret;
 
     /* Is it a plane? */
-    header_type = virPCIDeviceRead8(check, fd, PCI_HEADER_TYPE);
+    pci_device_cfg_read_u8(check->device, &header_type, PCI_HEADER_TYPE);
     if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
-        goto cleanup;
+        return ret;
 
-    secondary   = virPCIDeviceRead8(check, fd, PCI_SECONDARY_BUS);
-    subordinate = virPCIDeviceRead8(check, fd, PCI_SUBORDINATE_BUS);
+    pci_device_cfg_read_u8(check->device, &secondary, PCI_SECONDARY_BUS);
+    pci_device_cfg_read_u8(check->device, &subordinate, PCI_SUBORDINATE_BUS);
 
     VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
 
@@ -838,8 +696,7 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
      * the direct parent.  No further work is necessary
      */
     if (dev->address.bus == secondary) {
-        ret = 1;
-        goto cleanup;
+        return 1;
     }
 
     /* otherwise, SRIOV allows VFs to be on different buses than their PFs.
@@ -850,35 +707,26 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
         if (*best == NULL) {
             *best = virPCIDeviceNew(&check->address);
             if (*best == NULL) {
-                ret = -1;
-                goto cleanup;
+                return -1;
             }
         } else {
             /* OK, we had already recorded a previous "best" match for the
              * parent.  See if the current device is more restrictive than the
              * best, and if so, make it the new best
              */
-            int bestfd;
             uint8_t best_secondary;
 
-            if ((bestfd = virPCIDeviceConfigOpenTry(*best)) < 0)
-                goto cleanup;
-            best_secondary = virPCIDeviceRead8(*best, bestfd, PCI_SECONDARY_BUS);
-            virPCIDeviceConfigClose(*best, bestfd);
+            pci_device_cfg_read_u8((*best)->device, &best_secondary, PCI_SECONDARY_BUS);
 
             if (secondary > best_secondary) {
                 virPCIDeviceFree(*best);
                 *best = virPCIDeviceNew(&check->address);
                 if (*best == NULL) {
-                    ret = -1;
-                    goto cleanup;
+                    return -1;
                 }
             }
         }
     }
-
- cleanup:
-    virPCIDeviceConfigClose(check, fd);
     return ret;
 }
 
@@ -902,15 +750,14 @@ virPCIDeviceGetParent(virPCIDevice *dev, virPCIDevice **parent)
  */
 static int
 virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
-                                 int cfgfd,
                                  virPCIDeviceList *inactiveDevs)
 {
     g_autoptr(virPCIDevice) parent = NULL;
     g_autoptr(virPCIDevice) conflict = NULL;
     uint8_t config_space[PCI_CONF_LEN];
     uint16_t ctl;
-    int ret = -1;
-    int parentfd;
+    pciaddr_t bytes_read;
+    pciaddr_t bytes_written;
 
     /* Refuse to do a secondary bus reset if there are other
      * devices/functions behind the bus are used by the host
@@ -932,8 +779,6 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
                        dev->name);
         return -1;
     }
-    if ((parentfd = virPCIDeviceConfigOpenWrite(parent)) < 0)
-        goto out;
 
     VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);
 
@@ -941,38 +786,37 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
      * for the supplied device since we refuse to do a reset if there
      * are multiple devices/functions
      */
-    if (virPCIDeviceRead(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+    pci_device_cfg_read(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_read);
+    if (bytes_read < PCI_CONF_LEN) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to read PCI config space for %1$s"),
                        dev->name);
-        goto out;
+        return -1;
     }
 
     /* Read the control register, set the reset flag, wait 200ms,
      * unset the reset flag and wait 200ms.
      */
-    ctl = virPCIDeviceRead16(dev, parentfd, PCI_BRIDGE_CONTROL);
 
-    virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL,
-                        ctl | PCI_BRIDGE_CTL_RESET);
+    pci_device_cfg_read_u16(parent->device, &ctl, PCI_BRIDGE_CONTROL);
+
+    pci_device_cfg_write_u16(parent->device, ctl | PCI_BRIDGE_CTL_RESET, PCI_BRIDGE_CONTROL);
 
     g_usleep(200 * 1000); /* sleep 200ms */
 
-    virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, ctl);
+    pci_device_cfg_write_u16(parent->device, ctl, PCI_BRIDGE_CONTROL);
 
     g_usleep(200 * 1000); /* sleep 200ms */
 
-    if (virPCIDeviceWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+    pci_device_cfg_write(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_written);
+    if (bytes_written < PCI_CONF_LEN) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to restore PCI config space for %1$s"),
                        dev->name);
-        goto out;
+        return -1;
     }
-    ret = 0;
 
- out:
-    virPCIDeviceConfigClose(parent, parentfd);
-    return ret;
+    return 0;
 }
 
 /* Power management reset attempts to reset a device using a
@@ -980,16 +824,19 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
  * above we require the device supports a full internal reset.
  */
 static int
-virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceTryPowerManagementReset(virPCIDevice *dev)
 {
     uint8_t config_space[PCI_CONF_LEN];
     uint32_t ctl;
+    pciaddr_t bytes_read;
+    pciaddr_t bytes_written;
 
     if (!dev->pci_pm_cap_pos)
         return -1;
 
     /* Save and restore the device's config space. */
-    if (virPCIDeviceRead(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+    pci_device_cfg_read(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_read);
+    if (bytes_read < PCI_CONF_LEN) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to read PCI config space for %1$s"),
                        dev->name);
@@ -998,20 +845,19 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
 
     VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);
 
-    ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+    pci_device_cfg_read_u32(dev->device, &ctl, dev->pci_pm_cap_pos + PCI_PM_CTRL);
     ctl &= ~PCI_PM_CTRL_STATE_MASK;
 
-    virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
-                        ctl | PCI_PM_CTRL_STATE_D3hot);
+    pci_device_cfg_write_u32(dev->device, ctl | PCI_PM_CTRL_STATE_D3hot, dev->pci_pm_cap_pos + PCI_PM_CTRL);
 
     g_usleep(10 * 1000); /* sleep 10ms */
 
-    virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
-                        ctl | PCI_PM_CTRL_STATE_D0);
+    pci_device_cfg_write_u32(dev->device, ctl | PCI_PM_CTRL_STATE_D0, dev->pci_pm_cap_pos + PCI_PM_CTRL);
 
     g_usleep(10 * 1000); /* sleep 10ms */
 
-    if (virPCIDeviceWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+    pci_device_cfg_write(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_written);
+    if (bytes_written < PCI_CONF_LEN) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to restore PCI config space for %1$s"),
                        dev->name);
@@ -1046,10 +892,10 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
  * Always returns success (0) (for now)
  */
 static int
-virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
+virPCIDeviceInit(virPCIDevice *dev)
 {
     dev->is_pcie = false;
-    if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
+    if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
         /* an unprivileged process is unable to read *all* of a
          * device's PCI config (it can only read the first 64
          * bytes, which isn't enough for see the Express
@@ -1065,18 +911,13 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
          * -1), then we blindly assume the most likely outcome -
          * PCIe.
          */
-        off_t configLen = virFileLength(virPCIDeviceGetConfigPath(dev), -1);
-
-        if (configLen != 256)
-            dev->is_pcie = true;
-
     } else {
         dev->is_pcie = (dev->pcie_cap_pos != 0);
     }
 
-    virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
-    dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev, cfgfd);
-    dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev, cfgfd);
+    virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
+    dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev);
+    dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev);
 
     return 0;
 }
@@ -1089,7 +930,6 @@ virPCIDeviceReset(virPCIDevice *dev,
     g_autofree char *drvName = NULL;
     virPCIStubDriver drvType;
     int ret = -1;
-    int fd = -1;
     int hdrType = -1;
 
     if (virPCIGetHeaderType(dev, &hdrType) < 0)
@@ -1114,29 +954,26 @@ virPCIDeviceReset(virPCIDevice *dev,
      * be redundant.
      */
     if (virPCIDeviceGetCurrentDriverNameAndType(dev, &drvName, &drvType) < 0)
-        goto cleanup;
+        return -1;
 
     if (drvType == VIR_PCI_STUB_DRIVER_VFIO) {
 
         VIR_DEBUG("Device %s is bound to %s - skip reset", dev->name, drvName);
         ret = 0;
-        goto cleanup;
+        return 0;
     }
 
     VIR_DEBUG("Resetting device %s", dev->name);
 
-    if ((fd = virPCIDeviceConfigOpenWrite(dev)) < 0)
-        goto cleanup;
-
-    if (virPCIDeviceInit(dev, fd) < 0)
-        goto cleanup;
+    if (virPCIDeviceInit(dev) < 0)
+        return -1;
 
     /* KVM will perform FLR when starting and stopping
      * a guest, so there is no need for us to do it here.
      */
     if (dev->has_flr) {
         ret = 0;
-        goto cleanup;
+        return 0;
     }
 
     /* If the device supports PCI power management reset,
@@ -1144,11 +981,11 @@ virPCIDeviceReset(virPCIDevice *dev,
      * the function, not the whole device.
      */
     if (dev->has_pm_reset)
-        ret = virPCIDeviceTryPowerManagementReset(dev, fd);
+        ret = virPCIDeviceTryPowerManagementReset(dev);
 
     /* Bus reset is not an option with the root bus */
     if (ret < 0 && dev->address.bus != 0)
-        ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
+        ret = virPCIDeviceTrySecondaryBusReset(dev, inactiveDevs);
 
     if (ret < 0) {
         virErrorPtr err = virGetLastError();
@@ -1159,8 +996,6 @@ virPCIDeviceReset(virPCIDevice *dev,
                        _("no FLR, PM reset or bus reset available"));
     }
 
- cleanup:
-    virPCIDeviceConfigClose(dev, fd);
     return ret;
 }
 
@@ -1756,28 +1591,6 @@ virPCIDeviceReattach(virPCIDevice *dev,
     return 0;
 }
 
-static char *
-virPCIDeviceReadID(virPCIDevice *dev, const char *id_name)
-{
-    g_autofree char *path = NULL;
-    g_autofree char *id_str = NULL;
-
-    path = virPCIFile(dev->name, id_name);
-
-    /* ID string is '0xNNNN\n' ... i.e. 7 bytes */
-    if (virFileReadAll(path, 7, &id_str) < 0)
-        return NULL;
-
-    /* Check for 0x suffix */
-    if (id_str[0] != '0' || id_str[1] != 'x')
-        return NULL;
-
-    /* Chop off the newline; we know the string is 7 bytes */
-    id_str[6] = '\0';
-
-    return g_steal_pointer(&id_str);
-}
-
 bool
 virPCIDeviceAddressIsValid(virPCIDeviceAddress *addr,
                            bool report)
@@ -1865,9 +1678,9 @@ virPCIDeviceExists(const virPCIDeviceAddress *addr)
 virPCIDevice *
 virPCIDeviceNew(const virPCIDeviceAddress *address)
 {
+    struct pci_device * device;
+
     g_autoptr(virPCIDevice) dev = NULL;
-    g_autofree char *vendor = NULL;
-    g_autofree char *product = NULL;
 
     dev = g_new0(virPCIDevice, 1);
 
@@ -1875,31 +1688,21 @@ virPCIDeviceNew(const virPCIDeviceAddress *address)
 
     dev->name = virPCIDeviceAddressAsString(&dev->address);
 
-    dev->path = g_strdup_printf(PCI_SYSFS "devices/%s/config", dev->name);
-
-    if (!virFileExists(dev->path)) {
-        virReportSystemError(errno,
-                             _("Device %1$s not found: could not access %2$s"),
-                             dev->name, dev->path);
+    pci_system_init();
+    device = pci_device_find_by_slot(address->domain, address->bus, address->slot, address->function);
+    if (!device)
         return NULL;
-    }
-
-    vendor  = virPCIDeviceReadID(dev, "vendor");
-    product = virPCIDeviceReadID(dev, "device");
-
-    if (!vendor || !product) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to read product/vendor ID for %1$s"),
-                       dev->name);
+    dev->device = g_memdup(device, sizeof(*dev->device));
+    if (!dev->device) {
+        virReportSystemError(errno,
+                             _("Not found device domain: %1$d, bus: %2$d, slot: %3$d, function: %4$d"),
+                             address->domain, address->bus, address->slot, address->function);
         return NULL;
     }
-
-    /* strings contain '0x' prefix */
-    if (g_snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2],
-                   &product[2]) >= sizeof(dev->id)) {
+    if (g_snprintf(dev->id, sizeof(dev->id), "%x %x", dev->device->vendor_id, dev->device->device_id) >= sizeof(dev->id)) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("dev->id buffer overflow: %1$s %2$s"),
-                       &vendor[2], &product[2]);
+                       _("dev->id buffer overflow: %1$d %2$d"),
+                       dev->device->vendor_id, dev->device->device_id);
         return NULL;
     }
 
@@ -1918,10 +1721,10 @@ virPCIDeviceCopy(virPCIDevice *dev)
 
     /* shallow copy to take care of most attributes */
     *copy = *dev;
-    copy->path = NULL;
-    copy->used_by_drvname = copy->used_by_domname = NULL;
+    copy->device = NULL;
+    copy->device = g_memdup(dev->device, sizeof(*dev->device));
+    copy->name = copy->used_by_drvname = copy->used_by_domname = copy->stubDriverName = NULL;
     copy->name = g_strdup(dev->name);
-    copy->path = g_strdup(dev->path);
     copy->used_by_drvname = g_strdup(dev->used_by_drvname);
     copy->used_by_domname = g_strdup(dev->used_by_domname);
     copy->stubDriverName = g_strdup(dev->stubDriverName);
@@ -1936,10 +1739,11 @@ virPCIDeviceFree(virPCIDevice *dev)
         return;
     VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
     g_free(dev->name);
-    g_free(dev->path);
     g_free(dev->used_by_drvname);
     g_free(dev->used_by_domname);
     g_free(dev->stubDriverName);
+    if (dev->device)
+        g_free(dev->device);
     g_free(dev);
 }
 
@@ -1971,9 +1775,9 @@ virPCIDeviceGetName(virPCIDevice *dev)
  * config file.
  */
 const char *
-virPCIDeviceGetConfigPath(virPCIDevice *dev)
+virPCIDeviceGetConfigPath(virPCIDevice *dev G_GNUC_UNUSED)
 {
-    return dev->path;
+    return NULL;
 }
 
 void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed)
@@ -2484,47 +2288,37 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev)
     uint16_t flags;
     uint16_t ctrl;
     unsigned int pos;
-    int fd;
-    int ret = 0;
     uint16_t device_class;
 
-    if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
+    if (virPCIDeviceInit(dev) < 0) {
         return -1;
-
-    if (virPCIDeviceInit(dev, fd) < 0) {
-        ret = -1;
-        goto cleanup;
     }
 
     if (virPCIDeviceReadClass(dev, &device_class) < 0)
-        goto cleanup;
+        return 0;
 
     pos = dev->pcie_cap_pos;
     if (!pos || device_class != PCI_CLASS_BRIDGE_PCI)
-        goto cleanup;
+        return 0;
 
-    flags = virPCIDeviceRead16(dev, fd, pos + PCI_EXP_FLAGS);
+    pci_device_cfg_read_u16(dev->device, &flags, pos + PCI_EXP_FLAGS);
     if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM)
-        goto cleanup;
+        return 0;
 
-    pos = virPCIDeviceFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS);
+    pos = virPCIDeviceFindExtendedCapabilityOffset(dev, PCI_EXT_CAP_ID_ACS);
     if (!pos) {
         VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name);
-        ret = 1;
-        goto cleanup;
+        return 1;
     }
 
-    ctrl = virPCIDeviceRead16(dev, fd, pos + PCI_EXT_ACS_CTRL);
+    pci_device_cfg_read_u16(dev->device, &ctrl, pos + PCI_EXT_ACS_CTRL);
     if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) {
         VIR_DEBUG("%s %s: downstream port has ACS disabled",
                   dev->id, dev->name);
-        ret = 1;
-        goto cleanup;
+        return 1;
     }
 
- cleanup:
-    virPCIDeviceConfigClose(dev, fd);
-    return ret;
+    return 0;
 }
 
 static int
@@ -3189,48 +2983,27 @@ virPCIDeviceGetVPD(virPCIDevice *dev G_GNUC_UNUSED)
 int
 virPCIDeviceIsPCIExpress(virPCIDevice *dev)
 {
-    int fd;
-    int ret = -1;
-
-    if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
-        return ret;
-
-    if (virPCIDeviceInit(dev, fd) < 0)
-        goto cleanup;
-
-    ret = dev->is_pcie;
+    if (virPCIDeviceInit(dev) < 0)
+        return -1;
 
- cleanup:
-    virPCIDeviceConfigClose(dev, fd);
-    return ret;
+    return dev->is_pcie;
 }
 
 int
 virPCIDeviceHasPCIExpressLink(virPCIDevice *dev)
 {
-    int fd;
-    int ret = -1;
     uint16_t cap, type;
-
-    if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
-        return ret;
-
-    if (virPCIDeviceInit(dev, fd) < 0)
-        goto cleanup;
+    if (virPCIDeviceInit(dev) < 0)
+        return -1;
 
     if (dev->pcie_cap_pos == 0) {
-        ret = 0;
-        goto cleanup;
+        return 0;
     }
 
-    cap = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_CAP_FLAGS);
+    pci_device_cfg_read_u16(dev->device, &cap, dev->pcie_cap_pos + PCI_CAP_FLAGS);
     type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;
 
-    ret = type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;
-
- cleanup:
-    virPCIDeviceConfigClose(dev, fd);
-    return ret;
+    return type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;
 }
 
 int
@@ -3242,53 +3015,39 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev,
                           unsigned int *sta_width)
 {
     uint32_t t;
-    int fd;
-    int ret = -1;
-
-    if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
-        return ret;
-
-    if (virPCIDeviceInit(dev, fd) < 0)
-        goto cleanup;
+    uint16_t t16;
+    if (virPCIDeviceInit(dev) < 0)
+        return -1;
 
     if (!dev->pcie_cap_pos) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("pci device %1$s is not a PCI-Express device"),
                        dev->name);
-        goto cleanup;
+        return -1;
     }
 
-    t = virPCIDeviceRead32(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
+    pci_device_cfg_read_u32(dev->device, &t, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
 
     *cap_port = t >> 24;
     *cap_speed = t & PCI_EXP_LNKCAP_SPEED;
     *cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;
 
-    t = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+    pci_device_cfg_read_u16(dev->device, &t16, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+    t = t16;
 
     *sta_speed = t & PCI_EXP_LNKSTA_SPEED;
     *sta_width = (t & PCI_EXP_LNKSTA_WIDTH) >> 4;
-    ret = 0;
-
- cleanup:
-    virPCIDeviceConfigClose(dev, fd);
-    return ret;
+    return 0;
 }
 
 
 int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType)
 {
-    int fd;
     uint8_t type;
 
     *hdrType = -1;
 
-    if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
-        return -1;
-
-    type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);
-
-    virPCIDeviceConfigClose(dev, fd);
+    pci_device_cfg_read_u8(dev->device, &type, PCI_HEADER_TYPE);
 
     type &= PCI_HEADER_TYPE_MASK;
     if (type >= VIR_PCI_HEADER_LAST) {
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index d2a1f5acf1..fd8339bd30 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -18,12 +18,14 @@
  */
 
 #include <config.h>
+#include "testutils.h"
+
+#ifdef __linux__
 
 #include "qemu/qemu_alias.h"
 #include "qemu/qemu_conf.h"
 #include "qemu/qemu_hotplug.h"
 #include "qemumonitortestutils.h"
-#include "testutils.h"
 #include "testutilsqemu.h"
 #include "testutilsqemuschema.h"
 #include "virhostdev.h"
@@ -816,3 +818,10 @@ VIR_TEST_MAIN_PRELOAD(mymain,
                       VIR_TEST_MOCK("domaincaps"),
                       VIR_TEST_MOCK("virprocess"),
                       VIR_TEST_MOCK("qemuhotplug"));
+#else
+int
+main(void)
+{
+    return EXIT_AM_SKIP;
+}
+#endif
diff --git a/tests/qemumemlocktest.c b/tests/qemumemlocktest.c
index a2888732f7..5f62c80665 100644
--- a/tests/qemumemlocktest.c
+++ b/tests/qemumemlocktest.c
@@ -7,6 +7,8 @@
 
 #include "testutils.h"
 
+#ifdef __linux__
+
 #ifdef WITH_QEMU
 
 # include "internal.h"
@@ -137,3 +139,10 @@ main(void)
 }
 
 #endif /* WITH_QEMU */
+#else
+int
+main(void)
+{
+    return EXIT_AM_SKIP;
+}
+#endif
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 1f0068864a..6f84812109 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -7,6 +7,8 @@
 
 #include "testutils.h"
 
+#ifdef __linux__
+
 #ifdef WITH_QEMU
 
 # include "internal.h"
@@ -3051,3 +3053,10 @@ int main(void)
 }
 
 #endif /* WITH_QEMU */
+#else
+int
+main(void)
+{
+    return EXIT_AM_SKIP;
+}
+#endif
diff --git a/tests/virpcimock.c b/tests/virpcimock.c
index 5b923c63ce..36bb57edb0 100644
--- a/tests/virpcimock.c
+++ b/tests/virpcimock.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (C) 2024-2025 Future Crew, LLC
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
 
 #include "virpcivpdpriv.h"
 
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+#if defined(__linux__) || defined(__APPLE__)
 # define VIR_MOCK_LOOKUP_MAIN
 # include "virmock.h"
 # include "virpci.h"
@@ -42,6 +43,10 @@ static int (*real___open_2)(const char *path, int flags);
 static int (*real_close)(int fd);
 static DIR * (*real_opendir)(const char *name);
 static char *(*real_virFileCanonicalizePath)(const char *path);
+static int (*real_scandir)(const char *restrict dirp,
+            struct dirent ***restrict namelist,
+            typeof(int(const struct dirent *)) *filter,
+            typeof(int(const struct dirent **, const struct dirent **)) *compar);
 
 static char *fakerootdir;
 
@@ -955,6 +960,7 @@ init_syms(void)
     VIR_MOCK_REAL_INIT(opendir);
 # endif
     VIR_MOCK_REAL_INIT(virFileCanonicalizePath);
+    VIR_MOCK_REAL_INIT(scandir);
 }
 
 static void
@@ -1172,6 +1178,20 @@ virFileCanonicalizePath(const char *path)
     return real_virFileCanonicalizePath(newpath);
 }
 
+int scandir(const char *restrict dirp, struct dirent ***restrict namelist,
+            typeof(int(const struct dirent *)) *filter,
+            typeof(int(const struct dirent **, const struct dirent **)) *compar)
+{
+    g_autofree char *newpath = NULL;
+
+    init_syms();
+
+    if (getrealpath(&newpath, dirp) < 0)
+        return -1;
+
+    return real_scandir(newpath, namelist, filter, compar);
+}
+
 # include "virmockstathelpers.c"
 
 #else
-- 
2.47.1



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux