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;
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