Linux gets the list via sysfs. FreeBSD can get the list through ioctl Sponsored by: Future Crew, LLC Signed-off-by: Alexander Shursha <kekek2@xxxxx> --- src/bhyve/bhyve_capabilities.c | 2 +- src/conf/node_device_conf.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/util/virmdev.c | 2 +- src/util/virpci.c | 400 ++++++++++++++++++++++++++- 5 files changed, 399 insertions(+), 9 deletions(-) diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c index b065256cf0..fcef91c435 100644 --- a/src/bhyve/bhyve_capabilities.c +++ b/src/bhyve/bhyve_capabilities.c @@ -108,7 +108,7 @@ virBhyveDomainCapsFill(virDomainCaps *caps, VIR_DOMAIN_CAPS_ENUM_SET(caps->video.modelType, VIR_DOMAIN_VIDEO_TYPE_GOP); } - caps->hostdev.supported = VIR_TRISTATE_BOOL_NO; + caps->hostdev.supported = VIR_TRISTATE_BOOL_YES; caps->features[VIR_DOMAIN_CAPS_FEATURE_IOTHREADS] = VIR_TRISTATE_BOOL_NO; caps->features[VIR_DOMAIN_CAPS_FEATURE_VMCOREINFO] = VIR_TRISTATE_BOOL_NO; caps->features[VIR_DOMAIN_CAPS_FEATURE_GENID] = VIR_TRISTATE_BOOL_NO; diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 08a89942ba..39e6b78f3d 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2836,7 +2836,7 @@ virNodeDeviceSyncMdevActiveConfig(virNodeDeviceDef *def) } } -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHost *scsi_host) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index fa5db0d5d5..282af02724 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -111,7 +111,7 @@ int nodeConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED) return 1; } -#if defined (__linux__) && defined(WITH_UDEV) +#if (defined(__linux__) || defined(__FreeBSD__)) && defined(WITH_UDEV) /* NB: It was previously believed that changes in driver name were * relayed to libvirt as "change" events by udev, and the udev event * notification is setup to recognize such events and effectively diff --git a/src/util/virmdev.c b/src/util/virmdev.c index 6ecdbdf0ab..3a07ba75f2 100644 --- a/src/util/virmdev.c +++ b/src/util/virmdev.c @@ -565,7 +565,7 @@ virMediatedDeviceParentGetAddress(const char *sysfspath, return -1; } -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) ssize_t virMediatedDeviceGetMdevTypes(const char *sysfspath, diff --git a/src/util/virpci.c b/src/util/virpci.c index 90617e69c6..f954ce4df2 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -30,6 +30,13 @@ #include <sys/stat.h> #include <unistd.h> +#ifdef __FreeBSD__ +# ifdef WITH_BHYVE +# include <libudev.h> +# endif +# include <sys/pciio.h> +#endif + #ifdef __linux__ # include <sys/utsname.h> #endif @@ -72,7 +79,11 @@ struct _virPCIDevice { char *name; /* domain:bus:slot.function */ char id[PCI_ID_LEN]; /* product vendor */ +#ifndef __FreeBSD__ char *path; +#else + struct pci_match_conf patterns[1]; +#endif /* The driver:domain which uses the device */ char *used_by_drvname; @@ -99,6 +110,9 @@ struct _virPCIDevice { bool unbind_from_stub; bool remove_slot; bool reprobe; +#ifdef __FreeBSD__ + u_int8_t pc_hdr; /* PCI header type */ +#endif }; struct _virPCIDeviceList { @@ -359,6 +373,7 @@ virPCIDeviceGetCurrentDriverNameAndType(virPCIDevice *dev, } +#ifndef __FreeBSD__ static int virPCIDeviceConfigOpenInternal(virPCIDevice *dev, bool readonly, bool fatal) { @@ -429,6 +444,7 @@ virPCIDeviceRead(virPCIDevice *dev, return 0; } +#endif /** * virPCIDeviceReadN: @@ -450,6 +466,7 @@ virPCIDeviceRead(virPCIDevice *dev, * and the return value is 0, then the config file really does contain * the value 0 at @pos. */ +#ifndef __FreeBSD__ static uint8_t virPCIDeviceRead8(virPCIDevice *dev, int cfgfd, unsigned int pos) { @@ -473,7 +490,56 @@ virPCIDeviceRead32(virPCIDevice *dev, int cfgfd, unsigned int pos) virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf)); return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } +#else +static int +virPCIDeviceRead(virPCIDevice *dev, int pi_reg, int pi_width, u_int32_t *pi_data) +{ + struct pci_io pc; + int fd; + + bzero(&pc, sizeof(struct pci_io)); + pc.pi_sel.pc_domain = dev->address.domain; + pc.pi_sel.pc_bus = dev->address.bus; + pc.pi_sel.pc_dev = dev->address.slot; + pc.pi_sel.pc_func = dev->address.function; + pc.pi_reg = pi_reg; + pc.pi_width = pi_width; + + fd = open("/dev/pci", O_RDWR, 0); + errno = 0; + if (ioctl(fd, PCIOCREAD, &pc) == -1) { + VIR_FORCE_CLOSE(fd); + VIR_WARN("Failed to read from '%s' : %s", dev->name, g_strerror(errno)); + return -1; + } + VIR_FORCE_CLOSE(fd); + *pi_data = pc.pi_data; + return 0; +} +static uint8_t +virPCIDeviceRead8(virPCIDevice *dev, int pi_reg) +{ + u_int32_t pi_data; + virPCIDeviceRead(dev, pi_reg, 1, &pi_data); + return pi_data & 0xff; +} +static uint16_t +virPCIDeviceRead16(virPCIDevice *dev, int pi_reg) +{ + u_int32_t pi_data; + virPCIDeviceRead(dev, pi_reg, 2, &pi_data); + return pi_data & 0xffff; +} + +static uint32_t +virPCIDeviceRead32(virPCIDevice *dev, int pi_reg) +{ + u_int32_t pi_data; + virPCIDeviceRead(dev, pi_reg, 4, &pi_data); + return pi_data; +} +#endif static int virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class) { @@ -499,6 +565,7 @@ virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class) return 0; } +#ifndef __FreeBSD__ static int virPCIDeviceWrite(virPCIDevice *dev, int cfgfd, @@ -528,6 +595,44 @@ 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)); } +#else +static int +virPCIDeviceWrite(virPCIDevice *dev, int pi_reg, int pi_width, u_int32_t pi_data) +{ + struct pci_io pc; + int fd; + + bzero(&pc, sizeof(struct pci_io)); + pc.pi_sel.pc_domain = dev->address.domain; + pc.pi_sel.pc_bus = dev->address.bus; + pc.pi_sel.pc_dev = dev->address.slot; + pc.pi_sel.pc_func = dev->address.function; + pc.pi_reg = pi_reg; + pc.pi_width = pi_width; + pc.pi_data = pi_data; + + fd = open("/dev/pci", O_RDWR, 0); + errno = 0; + if (ioctl(fd, PCIOCWRITE, &pc) == -1) { + VIR_FORCE_CLOSE(fd); + VIR_WARN("Failed to write to '%s' : %s", dev->name, g_strerror(errno)); + return -1; + } + VIR_FORCE_CLOSE(fd); + return 0; +} +static void +virPCIDeviceWrite16(virPCIDevice *dev, int pi_reg, u_int16_t val) +{ + virPCIDeviceWrite(dev, pi_reg, 2, val); +} + +static void +virPCIDeviceWrite32(virPCIDevice *dev, int pi_reg, uint32_t val) +{ + virPCIDeviceWrite(dev, pi_reg, 4, val); +} +#endif typedef int (*virPCIDeviceIterPredicate)(virPCIDevice *, virPCIDevice *, void *); @@ -610,7 +715,9 @@ virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate, */ static int virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, +#ifndef __FreeBSD__ int cfgfd, +#endif unsigned int capability, unsigned int *offset) { @@ -619,11 +726,19 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, *offset = 0; /* assume failure (*nothing* can be at offset 0) */ +#ifndef __FreeBSD__ status = virPCIDeviceRead16(dev, cfgfd, PCI_STATUS); +#else + status = virPCIDeviceRead16(dev, PCI_STATUS); +#endif if (errno != 0 || !(status & PCI_STATUS_CAP_LIST)) goto error; +#ifndef __FreeBSD__ pos = virPCIDeviceRead8(dev, cfgfd, PCI_CAPABILITY_LIST); +#else + pos = virPCIDeviceRead8(dev, PCI_CAPABILITY_LIST); +#endif if (errno != 0) goto error; @@ -635,7 +750,11 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, * capabilities here. */ while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) { +#ifndef __FreeBSD__ uint8_t capid = virPCIDeviceRead8(dev, cfgfd, pos); +#else + uint8_t capid = virPCIDeviceRead8(dev, pos); +#endif if (errno != 0) goto error; @@ -646,7 +765,11 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, return 0; } +#ifndef __FreeBSD__ pos = virPCIDeviceRead8(dev, cfgfd, pos + 1); +#else + pos = virPCIDeviceRead8(dev, pos + 1); +#endif if (errno != 0) goto error; } @@ -665,7 +788,9 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev, static unsigned int virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev, +#ifndef __FreeBSD__ int cfgfd, +#endif unsigned int capability) { int ttl; @@ -677,7 +802,11 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev, pos = PCI_EXT_CAP_BASE; while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) { +#ifndef __FreeBSD__ header = virPCIDeviceRead32(dev, cfgfd, pos); +#else + header = virPCIDeviceRead32(dev, pos); +#endif if ((header & PCI_EXT_CAP_ID_MASK) == capability) return pos; @@ -693,7 +822,11 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev, * not have FLR, 1 if it does, and -1 on error */ static bool +#ifndef __FreeBSD__ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd) +#else +virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev) +#endif { uint32_t caps; unsigned int pos; @@ -707,7 +840,11 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd) * on SR-IOV NICs at the moment. */ if (dev->pcie_cap_pos) { +#ifndef __FreeBSD__ caps = virPCIDeviceRead32(dev, cfgfd, dev->pcie_cap_pos + PCI_EXP_DEVCAP); +#else + caps = virPCIDeviceRead32(dev, dev->pcie_cap_pos + PCI_EXP_DEVCAP); +#endif if (caps & PCI_EXP_DEVCAP_FLR) { VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name); return true; @@ -718,11 +855,19 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd) * the same thing, except for conventional PCI * devices. This is not common yet. */ +#ifndef __FreeBSD__ if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_AF, &pos) < 0) +#else + if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_AF, &pos) < 0) +#endif goto error; if (pos) { +#ifndef __FreeBSD__ caps = virPCIDeviceRead16(dev, cfgfd, pos + PCI_AF_CAP); +#else + caps = virPCIDeviceRead16(dev, pos + PCI_AF_CAP); +#endif if (caps & PCI_AF_CAP_FLR) { VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name); return true; @@ -754,13 +899,21 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd) * internal reset, not just a soft reset. */ static bool +#ifndef __FreeBSD__ virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev, int cfgfd) +#else +virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev) +#endif { if (dev->pci_pm_cap_pos) { uint32_t ctl; /* require the NO_SOFT_RESET bit is clear */ +#ifndef __FreeBSD__ ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL); +#else + ctl = virPCIDeviceRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL); +#endif if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) { VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name); return true; @@ -811,13 +964,17 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data) uint8_t header_type, secondary, subordinate; virPCIDevice **best = data; int ret = 0; +#ifndef __FreeBSD__ int fd; +#endif if (dev->address.domain != check->address.domain) return 0; +#ifndef __FreeBSD__ if ((fd = virPCIDeviceConfigOpenTry(check)) < 0) return 0; +#endif /* Is it a bridge? */ ret = virPCIDeviceReadClass(check, &device_class); @@ -825,12 +982,21 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data) goto cleanup; /* Is it a plane? */ +#ifndef __FreeBSD__ header_type = virPCIDeviceRead8(check, fd, PCI_HEADER_TYPE); +#else + header_type = virPCIDeviceRead8(check, PCI_HEADER_TYPE); +#endif if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) goto cleanup; +#ifndef __FreeBSD__ secondary = virPCIDeviceRead8(check, fd, PCI_SECONDARY_BUS); subordinate = virPCIDeviceRead8(check, fd, PCI_SUBORDINATE_BUS); +#else + secondary = virPCIDeviceRead8(check, PCI_SECONDARY_BUS); + subordinate = virPCIDeviceRead8(check, PCI_SUBORDINATE_BUS); +#endif VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name); @@ -858,13 +1024,19 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data) * parent. See if the current device is more restrictive than the * best, and if so, make it the new best */ +#ifndef __FreeBSD__ int bestfd; +#endif uint8_t best_secondary; +#ifndef __FreeBSD__ if ((bestfd = virPCIDeviceConfigOpenTry(*best)) < 0) goto cleanup; best_secondary = virPCIDeviceRead8(*best, bestfd, PCI_SECONDARY_BUS); virPCIDeviceConfigClose(*best, bestfd); +#else + best_secondary = virPCIDeviceRead8(*best, PCI_SECONDARY_BUS); +#endif if (secondary > best_secondary) { virPCIDeviceFree(*best); @@ -878,7 +1050,9 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data) } cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(check, fd); +#endif return ret; } @@ -902,7 +1076,9 @@ virPCIDeviceGetParent(virPCIDevice *dev, virPCIDevice **parent) */ static int virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, +#ifndef __FreeBSD__ int cfgfd, +#endif virPCIDeviceList *inactiveDevs) { g_autoptr(virPCIDevice) parent = NULL; @@ -910,7 +1086,9 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, uint8_t config_space[PCI_CONF_LEN]; uint16_t ctl; int ret = -1; +#ifndef __FreeBSD__ int parentfd; +#endif /* Refuse to do a secondary bus reset if there are other * devices/functions behind the bus are used by the host @@ -932,8 +1110,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, dev->name); return -1; } + +#ifndef __FreeBSD__ if ((parentfd = virPCIDeviceConfigOpenWrite(parent)) < 0) goto out; +#endif VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name); @@ -941,7 +1122,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, * for the supplied device since we refuse to do a reset if there * are multiple devices/functions */ +#ifndef __FreeBSD__ if (virPCIDeviceRead(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { +#else + if (virPCIDeviceRead(dev, 0, PCI_CONF_LEN, (u_int32_t *) config_space) < 0) { +#endif virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to read PCI config space for %1$s"), dev->name); @@ -951,6 +1136,7 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, /* Read the control register, set the reset flag, wait 200ms, * unset the reset flag and wait 200ms. */ +#ifndef __FreeBSD__ ctl = virPCIDeviceRead16(dev, parentfd, PCI_BRIDGE_CONTROL); virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, @@ -963,6 +1149,20 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, g_usleep(200 * 1000); /* sleep 200ms */ if (virPCIDeviceWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { +#else + ctl = virPCIDeviceRead16(parent, PCI_BRIDGE_CONTROL); + + virPCIDeviceWrite16(parent, PCI_BRIDGE_CONTROL, + ctl | PCI_BRIDGE_CTL_RESET); + + g_usleep(200 * 1000); /* sleep 200ms */ + + virPCIDeviceWrite16(parent, PCI_BRIDGE_CONTROL, ctl); + + g_usleep(200 * 1000); /* sleep 200ms */ + + if (virPCIDeviceWrite(dev, 0, PCI_CONF_LEN, (config_space[0] << 0) | (config_space[1] << 8) | (config_space[2] << 16) | (config_space[3] << 24)) < 0) { +#endif virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to restore PCI config space for %1$s"), dev->name); @@ -971,7 +1171,9 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, ret = 0; out: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(parent, parentfd); +#endif return ret; } @@ -980,7 +1182,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev, * above we require the device supports a full internal reset. */ static int +#ifndef __FreeBSD__ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd) +#else +virPCIDeviceTryPowerManagementReset(virPCIDevice *dev) +#endif { uint8_t config_space[PCI_CONF_LEN]; uint32_t ctl; @@ -989,6 +1195,7 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd) return -1; /* Save and restore the device's config space. */ +#ifndef __FreeBSD__ if (virPCIDeviceRead(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to read PCI config space for %1$s"), @@ -1012,6 +1219,31 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd) g_usleep(10 * 1000); /* sleep 10ms */ if (virPCIDeviceWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { +#else + if (virPCIDeviceRead(dev, 0, PCI_CONF_LEN, (u_int32_t *) config_space) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read PCI config space for %1$s"), + dev->name); + return -1; + } + + VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name); + + ctl = virPCIDeviceRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL); + ctl &= ~PCI_PM_CTRL_STATE_MASK; + + virPCIDeviceWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, + ctl | PCI_PM_CTRL_STATE_D3hot); + + g_usleep(10 * 1000); /* sleep 10ms */ + + virPCIDeviceWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, + ctl | PCI_PM_CTRL_STATE_D0); + + g_usleep(10 * 1000); /* sleep 10ms */ + + if (virPCIDeviceWrite(dev, 0, PCI_CONF_LEN, (config_space[0] << 0) | (config_space[1] << 8) | (config_space[2] << 16) | (config_space[3] << 24)) < 0) { +#endif virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to restore PCI config space for %1$s"), dev->name); @@ -1046,10 +1278,18 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd) * Always returns success (0) (for now) */ static int +#ifndef __FreeBSD__ virPCIDeviceInit(virPCIDevice *dev, int cfgfd) +#else +virPCIDeviceInit(virPCIDevice *dev) +#endif { dev->is_pcie = false; +#ifndef __FreeBSD__ if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) { +#else + if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) { +#endif /* 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,6 +1305,7 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd) * -1), then we blindly assume the most likely outcome - * PCIe. */ +#ifndef __FreeBSD__ off_t configLen = virFileLength(virPCIDeviceGetConfigPath(dev), -1); if (configLen != 256) @@ -1077,6 +1318,16 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd) 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); +#else + + } else { + dev->is_pcie = (dev->pcie_cap_pos != 0); + } + + virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos); + dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev); + dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev); +#endif return 0; } @@ -1089,7 +1340,9 @@ virPCIDeviceReset(virPCIDevice *dev, g_autofree char *drvName = NULL; virPCIStubDriver drvType; int ret = -1; +#ifndef __FreeBSD__ int fd = -1; +#endif int hdrType = -1; if (virPCIGetHeaderType(dev, &hdrType) < 0) @@ -1125,10 +1378,14 @@ virPCIDeviceReset(virPCIDevice *dev, VIR_DEBUG("Resetting device %s", dev->name); +#ifndef __FreeBSD__ if ((fd = virPCIDeviceConfigOpenWrite(dev)) < 0) goto cleanup; if (virPCIDeviceInit(dev, fd) < 0) +#else + if (virPCIDeviceInit(dev) < 0) +#endif goto cleanup; /* KVM will perform FLR when starting and stopping @@ -1144,11 +1401,19 @@ virPCIDeviceReset(virPCIDevice *dev, * the function, not the whole device. */ if (dev->has_pm_reset) +#ifndef __FreeBSD__ ret = virPCIDeviceTryPowerManagementReset(dev, fd); +#else + ret = virPCIDeviceTryPowerManagementReset(dev); +#endif /* Bus reset is not an option with the root bus */ if (ret < 0 && dev->address.bus != 0) +#ifndef __FreeBSD__ ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs); +#else + ret = virPCIDeviceTrySecondaryBusReset(dev, inactiveDevs); +#endif if (ret < 0) { virErrorPtr err = virGetLastError(); @@ -1160,7 +1425,9 @@ virPCIDeviceReset(virPCIDevice *dev, } cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(dev, fd); +#endif return ret; } @@ -1868,6 +2135,12 @@ virPCIDeviceNew(const virPCIDeviceAddress *address) g_autoptr(virPCIDevice) dev = NULL; g_autofree char *vendor = NULL; g_autofree char *product = NULL; +#ifdef __FreeBSD__ + struct pci_conf_io pc; + struct pci_match_conf patterns[1]; + struct pci_conf conf[1]; + int fd; +#endif dev = g_new0(virPCIDevice, 1); @@ -1875,6 +2148,7 @@ virPCIDeviceNew(const virPCIDeviceAddress *address) dev->name = virPCIDeviceAddressAsString(&dev->address); +#ifndef __FreeBSD__ dev->path = g_strdup_printf(PCI_SYSFS "devices/%s/config", dev->name); if (!virFileExists(dev->path)) { @@ -1902,6 +2176,52 @@ virPCIDeviceNew(const virPCIDeviceAddress *address) &vendor[2], &product[2]); return NULL; } +#else + fd = open("/dev/pci", O_RDONLY, 0); + if (fd < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Error open /dev/pci: %1$d"), errno); + return NULL; + } + + bzero(&pc, sizeof(struct pci_conf_io)); + pc.match_buf_len = sizeof(conf); + pc.matches = conf; + + bzero(patterns, sizeof(patterns)); + patterns[0].pc_sel.pc_domain = address->domain; + patterns[0].pc_sel.pc_bus = address->bus; + patterns[0].pc_sel.pc_dev = address->slot; + patterns[0].pc_sel.pc_func = address->function; + + patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; + pc.num_patterns = 1; + pc.pat_buf_len = sizeof(patterns); + pc.patterns = patterns; + + if (ioctl(fd, PCIOCGETCONF, &pc) == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("ioctl(PCIOCGETCONF) eroor: %1$d"), errno); + return NULL; + } + if (pc.status != PCI_GETCONF_LAST_DEVICE && pc.status != PCI_GETCONF_MORE_DEVS) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("error returned from PCIOCGETCONF ioctl: %1$d"), pc.status); + return NULL; + } + VIR_FORCE_CLOSE(fd); + if (pc.num_matches == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Device not found: %1$d"), pc.num_matches); + return NULL; + } + + /* strings contain '0x' prefix */ + if (g_snprintf(dev->id, sizeof(dev->id), "%x %x", pc.matches->pc_vendor, + pc.matches->pc_device) >= sizeof(dev->id)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("dev->id buffer overflow: %1$x %2$x"), + pc.matches->pc_vendor, pc.matches->pc_device); + return NULL; + } + dev->pc_hdr = pc.matches->pc_hdr; +#endif VIR_DEBUG("%s %s: initialized", dev->id, dev->name); @@ -1918,10 +2238,12 @@ virPCIDeviceCopy(virPCIDevice *dev) /* shallow copy to take care of most attributes */ *copy = *dev; +#ifndef __FreeBSD__ copy->path = NULL; + copy->path = g_strdup(dev->path); +#endif copy->used_by_drvname = copy->used_by_domname = 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,7 +2258,9 @@ virPCIDeviceFree(virPCIDevice *dev) return; VIR_DEBUG("%s %s: freeing", dev->id, dev->name); g_free(dev->name); +#ifndef __FreeBSD__ g_free(dev->path); +#endif g_free(dev->used_by_drvname); g_free(dev->used_by_domname); g_free(dev->stubDriverName); @@ -1970,11 +2294,19 @@ virPCIDeviceGetName(virPCIDevice *dev) * Returns a pointer to a string containing the path of @dev's PCI * config file. */ +#ifndef __FreeBSD__ const char * virPCIDeviceGetConfigPath(virPCIDevice *dev) { return dev->path; } +#else +const char * +virPCIDeviceGetConfigPath(virPCIDevice *dev G_GNUC_UNUSED) +{ + return NULL; +} +#endif void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed) { @@ -2484,14 +2816,20 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev) uint16_t flags; uint16_t ctrl; unsigned int pos; +#ifndef __FreeBSD__ int fd; +#endif int ret = 0; uint16_t device_class; +#ifndef __FreeBSD__ if ((fd = virPCIDeviceConfigOpen(dev)) < 0) return -1; if (virPCIDeviceInit(dev, fd) < 0) { +#else + if (virPCIDeviceInit(dev) < 0) { +#endif ret = -1; goto cleanup; } @@ -2503,18 +2841,30 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev) if (!pos || device_class != PCI_CLASS_BRIDGE_PCI) goto cleanup; +#ifndef __FreeBSD__ flags = virPCIDeviceRead16(dev, fd, pos + PCI_EXP_FLAGS); +#else + flags = virPCIDeviceRead16(dev, pos + PCI_EXP_FLAGS); +#endif if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM) goto cleanup; +#ifndef __FreeBSD__ pos = virPCIDeviceFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS); +#else + pos = virPCIDeviceFindExtendedCapabilityOffset(dev, PCI_EXT_CAP_ID_ACS); +#endif if (!pos) { VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name); ret = 1; goto cleanup; } +#ifndef __FreeBSD__ ctrl = virPCIDeviceRead16(dev, fd, pos + PCI_EXT_ACS_CTRL); +#else + ctrl = virPCIDeviceRead16(dev, pos + PCI_EXT_ACS_CTRL); +#endif 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); @@ -2523,7 +2873,9 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev) } cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(dev, fd); +#endif return ret; } @@ -2689,7 +3041,7 @@ virPCIGetVirtualFunctions(const char *sysfs_path, } -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) virPCIDeviceAddress * virPCIGetDeviceAddressFromSysfsLink(const char *device_link) @@ -3189,33 +3541,43 @@ virPCIDeviceGetVPD(virPCIDevice *dev G_GNUC_UNUSED) int virPCIDeviceIsPCIExpress(virPCIDevice *dev) { +int ret = -1; +#ifndef __FreeBSD__ int fd; - int ret = -1; if ((fd = virPCIDeviceConfigOpen(dev)) < 0) return ret; if (virPCIDeviceInit(dev, fd) < 0) +#else + if (virPCIDeviceInit(dev) < 0) +#endif goto cleanup; ret = dev->is_pcie; cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(dev, fd); +#endif return ret; } int virPCIDeviceHasPCIExpressLink(virPCIDevice *dev) { - int fd; int ret = -1; uint16_t cap, type; +#ifndef __FreeBSD__ + int fd; if ((fd = virPCIDeviceConfigOpen(dev)) < 0) return ret; if (virPCIDeviceInit(dev, fd) < 0) +#else + if (virPCIDeviceInit(dev) < 0) +#endif goto cleanup; if (dev->pcie_cap_pos == 0) { @@ -3223,13 +3585,19 @@ virPCIDeviceHasPCIExpressLink(virPCIDevice *dev) goto cleanup; } +#ifndef __FreeBSD__ cap = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_CAP_FLAGS); +#else + cap = virPCIDeviceRead16(dev, dev->pcie_cap_pos + PCI_CAP_FLAGS); +#endif type = (cap & PCI_EXP_FLAGS_TYPE) >> 4; ret = type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC; cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(dev, fd); +#endif return ret; } @@ -3242,13 +3610,17 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev, unsigned int *sta_width) { uint32_t t; - int fd; int ret = -1; +#ifndef __FreeBSD__ + int fd; if ((fd = virPCIDeviceConfigOpen(dev)) < 0) return ret; if (virPCIDeviceInit(dev, fd) < 0) +#else + if (virPCIDeviceInit(dev) < 0) +#endif goto cleanup; if (!dev->pcie_cap_pos) { @@ -3258,26 +3630,37 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev, goto cleanup; } +#ifndef __FreeBSD__ t = virPCIDeviceRead32(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKCAP); +#else + t = virPCIDeviceRead32(dev, dev->pcie_cap_pos + PCI_EXP_LNKCAP); +#endif *cap_port = t >> 24; *cap_speed = t & PCI_EXP_LNKCAP_SPEED; *cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4; +#ifndef __FreeBSD__ t = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKSTA); +#else + t = virPCIDeviceRead16(dev, dev->pcie_cap_pos + PCI_EXP_LNKSTA); +#endif *sta_speed = t & PCI_EXP_LNKSTA_SPEED; *sta_width = (t & PCI_EXP_LNKSTA_WIDTH) >> 4; ret = 0; cleanup: +#ifndef __FreeBSD__ virPCIDeviceConfigClose(dev, fd); +#endif return ret; } int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType) { +#ifndef __FreeBSD__ int fd; uint8_t type; @@ -3289,6 +3672,13 @@ int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType) type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE); virPCIDeviceConfigClose(dev, fd); +#else + uint8_t type = dev->pc_hdr; + + *hdrType = -1; + + type = virPCIDeviceRead8(dev, PCI_HEADER_TYPE); +#endif type &= PCI_HEADER_TYPE_MASK; if (type >= VIR_PCI_HEADER_LAST) { -- 2.47.1