Sponsored by: Future Crew, LLC Signed-off-by: Alexander Shursha <kekek2@xxxxx> --- src/meson.build | 1 + src/util/virpci.c | 464 ++++++++++------------------------------ tests/qemuhotplugtest.c | 11 +- tests/qemumemlocktest.c | 9 + tests/qemuxmlconftest.c | 9 + tests/virpcimock.c | 21 +- 6 files changed, 160 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..3f95fa2b3f 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <pciaccess.h> #ifdef __linux__ # include <sys/utsname.h> @@ -72,7 +73,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 +360,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 +385,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 +466,6 @@ virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate, */ static int virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, - int cfgfd, unsigned int capability, unsigned int *offset) { @@ -619,11 +474,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 +492,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 +505,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 +525,6 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, static unsigned int virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev, - int cfgfd, unsigned int capability) { int ttl; @@ -677,7 +536,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 +552,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 +566,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 +577,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 +615,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 +672,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 +695,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 +706,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 +749,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 +778,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 +785,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 +823,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 +844,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 +891,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 +910,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 +929,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 +953,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 +980,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 +995,6 @@ virPCIDeviceReset(virPCIDevice *dev, _("no FLR, PM reset or bus reset available")); } - cleanup: - virPCIDeviceConfigClose(dev, fd); return ret; } @@ -1756,28 +1590,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 +1677,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 +1687,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 +1720,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 +1738,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 +1774,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 +2287,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 +2982,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 +3014,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..2fa12903d2 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -22,7 +22,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 +42,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 +959,7 @@ init_syms(void) VIR_MOCK_REAL_INIT(opendir); # endif VIR_MOCK_REAL_INIT(virFileCanonicalizePath); + VIR_MOCK_REAL_INIT(scandir); } static void @@ -1172,6 +1177,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