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(a)ya.ru>
---
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