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

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

 



  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



[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