[PATCH 1/3] [bhyve] list pci devices on host

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux