Alexander Shursha wrote: > 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; Hi Alexander, thanks for the patches! I think this change requires fixing the tests/domaincapstest. You can run tests using 'ninja test'. > 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 > }; The util/virtpci.c is definitely not my area of knowledge, though it feels like there's probably a more general way to make these changes. Having different structs, fuction signatures and a lot of #ifdefs tells that this probably needs to be refactored to support more clear platform-specific implementations? Hopefully somebody could provide some suggestions what's the best way to do that. > 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