From 872acfce41203d493cc01308658c75ba1c872d5a Mon Sep 17 00:00:00 2001 From: Ryan Stone Date: Tue, 15 Apr 2014 23:02:40 -0400 Subject: [PATCH 07/21] Implement interface to create SR-IOV Virtual Functions Implement the interace to create SR-IOV Virtual Functions (VFs). When a driver registers that they support SR-IOV by calling pci_setup_iov(), the SR-IOV code creates a new node in /dev/iov for that device. An ioctl can be invoked on that device to create VFs and have the driver initialize them. At this point, allocating memory I/O windows (BARs) is not supported. --- sys/amd64/conf/GENERIC | 1 + sys/conf/files | 1 + sys/conf/options | 1 + sys/dev/pci/pci.c | 29 ++++ sys/dev/pci/pci_if.m | 24 +++ sys/dev/pci/pci_iov.c | 380 ++++++++++++++++++++++++++++++++++++++++++ sys/dev/pci/pci_iov_private.h | 40 +++++ sys/dev/pci/pci_private.h | 6 + sys/dev/pci/pcireg.h | 18 ++ sys/dev/pci/pcivar.h | 22 +++ sys/i386/conf/GENERIC | 1 + sys/sys/iov.h | 43 +++++ 12 files changed, 566 insertions(+) create mode 100755 sys/dev/pci/pci_iov.c create mode 100755 sys/dev/pci/pci_iov_private.h create mode 100755 sys/sys/iov.h diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 1c21758..e0ff09d 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -95,6 +95,7 @@ device cpufreq device acpi options ACPI_DMAR device pci +options PCI_IOV # PCI SR-IOV support # Floppy drives device fdc diff --git a/sys/conf/files b/sys/conf/files index d730cd6..ce3c2b99 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1980,6 +1980,7 @@ dev/pci/ignore_pci.c optional pci dev/pci/isa_pci.c optional pci isa dev/pci/pci.c optional pci dev/pci/pci_if.m standard +dev/pci/pci_iov.c optional pci pci_iov dev/pci/pci_pci.c optional pci dev/pci/pci_subr.c optional pci dev/pci/pci_user.c optional pci diff --git a/sys/conf/options b/sys/conf/options index fdc3530..f0a3267 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -166,6 +166,7 @@ NO_SYSCTL_DESCR opt_global.h NSWBUF_MIN opt_swap.h MBUF_PACKET_ZONE_DISABLE opt_global.h PANIC_REBOOT_WAIT_TIME opt_panic.h +PCI_IOV opt_global.h PPC_DEBUG opt_ppc.h PPC_PROBE_CHIPSET opt_ppc.h PPS_SYNC opt_ntp.h diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index e18ffc0..b08b3a2 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -189,6 +189,10 @@ static device_method_t pci_methods[] = { DEVMETHOD(pci_msi_count, pci_msi_count_method), DEVMETHOD(pci_msix_count, pci_msix_count_method), DEVMETHOD(pci_get_rid, pci_get_rid_method), +#ifdef PCI_IOV + DEVMETHOD(pci_iov_attach, pci_iov_attach_method), + DEVMETHOD(pci_iov_detach, pci_iov_detach_method), +#endif DEVMETHOD_END }; @@ -634,6 +638,8 @@ pci_fill_devinfo(device_t pcib, int d, int b, int s, int f, uint16_t vid, cfg->hdrtype &= ~PCIM_MFDEV; STAILQ_INIT(&cfg->maps); + cfg->iov = NULL; + pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); @@ -3535,6 +3541,29 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) #undef REG } +#ifdef PCI_IOV +device_t +pci_add_iov_child(device_t bus, size_t size, uint16_t rid, uint16_t vid, + uint16_t did, const char *driver) +{ + struct pci_devinfo *dinfo; + device_t pcib; + int busno, slot, func; + + pcib = device_get_parent(bus); + + PCIB_DECODE_RID(pcib, rid, &busno, &slot, &func); + + dinfo = pci_fill_devinfo(pcib, pci_get_domain(pcib), busno, slot, func, + vid, did, size); + + dinfo->cfg.flags |= PCICFG_VF; + pci_add_named_child(bus, dinfo, driver); + + return (dinfo->cfg.dev); +} +#endif + static void pci_add_named_child(device_t bus, struct pci_devinfo *dinfo, const char *name) { diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m index 82864eb..babf896 100644 --- a/sys/dev/pci/pci_if.m +++ b/sys/dev/pci/pci_if.m @@ -165,3 +165,27 @@ METHOD uint16_t get_rid { device_t child; }; +METHOD int iov_attach { + device_t dev; + device_t child; +}; + +METHOD int iov_detach { + device_t dev; + device_t child; +}; + +METHOD int init_iov { + device_t dev; + uint16_t num_vfs; +}; + +METHOD void uninit_iov { + device_t dev; +}; + +METHOD int add_vf { + device_t dev; + uint16_t vfnum; +}; + diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c new file mode 100755 index 0000000..3cc38bb --- /dev/null +++ b/sys/dev/pci/pci_iov.c @@ -0,0 +1,380 @@ +/*- + * Copyright (c) 2013-2014 Sandvine Inc. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "pci_if.h" +#include "pcib_if.h" + +static MALLOC_DEFINE(M_SRIOV, "sr_iov", "PCI SR-IOV allocations"); + +static d_ioctl_t pci_iov_ioctl; + +static struct cdevsw iov_cdevsw = { + .d_version = D_VERSION, + .d_name = "iov", + .d_ioctl = pci_iov_ioctl +}; + +#define IOV_READ(d, r, w) \ + pci_read_config((d)->cfg.dev, (d)->cfg.iov->iov_pos + r, w) + +#define IOV_WRITE(d, r, v, w) \ + pci_write_config((d)->cfg.dev, (d)->cfg.iov->iov_pos + r, v, w) + +int +pci_iov_attach_method(device_t bus, device_t dev) +{ + device_t pcib; + struct pci_devinfo *dinfo; + struct pcicfg_iov *iov; + uint32_t version; + int error; + int iov_pos; + + dinfo = device_get_ivars(dev); + pcib = device_get_parent(bus); + + error = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos); + + if (error != 0) + return (error); + + version = pci_read_config(dev, iov_pos, 4); + if (PCI_EXTCAP_VER(version) != 1) { + if (bootverbose) + device_printf(dev, + "Unsupported version of SR-IOV (%d) detected\n", + PCI_EXTCAP_VER(version)); + + return (ENXIO); + } + + iov = malloc(sizeof(*dinfo->cfg.iov), M_SRIOV, M_WAITOK | M_ZERO); + + mtx_lock(&Giant); + if (dinfo->cfg.iov != NULL) { + error = EBUSY; + goto cleanup; + } + + iov->iov_pos = iov_pos; + + iov->iov_cdev = make_dev(&iov_cdevsw, device_get_unit(dev), + UID_ROOT, GID_WHEEL, 0600, "iov/%s", device_get_nameunit(dev)); + + if (iov->iov_cdev == NULL) { + error = ENOMEM; + goto cleanup; + } + + dinfo->cfg.iov = iov; + iov->iov_cdev->si_drv1 = dinfo; + mtx_unlock(&Giant); + + return (0); + +cleanup: + free(iov, M_SRIOV); + mtx_unlock(&Giant); + return (error); +} + +int +pci_iov_detach_method(device_t bus, device_t dev) +{ + struct pci_devinfo *dinfo; + struct pcicfg_iov *iov; + + mtx_lock(&Giant); + dinfo = device_get_ivars(dev); + iov = dinfo->cfg.iov; + + if (iov == NULL) { + mtx_unlock(&Giant); + return (0); + } + + if (iov->iov_num_vfs != 0) { + mtx_unlock(&Giant); + return (EBUSY); + } + + dinfo->cfg.iov = NULL; + + if (iov->iov_cdev) { + destroy_dev(iov->iov_cdev); + iov->iov_cdev = NULL; + } + + free(iov, M_SRIOV); + mtx_unlock(&Giant); + + return (0); +} + +/* + * Set the ARI_EN bit in the lowest-numbered PCI function with the SR-IOV + * capability. This bit is only writeable on the lowest-numbered PF but + * affects all PFs on the device. + */ +static int +pci_iov_set_ari(device_t bus) +{ + device_t lowest; + device_t *devlist; + int i, error, devcount, lowest_func, lowest_pos, iov_pos, dev_func; + uint16_t iov_ctl; + + /* If ARI is disabled on the downstream port there is nothing to do. */ + if (!PCIB_ARI_ENABLED(device_get_parent(bus))) + return (0); + + error = device_get_children(bus, &devlist, &devcount); + + if (error != 0) + return (error); + + lowest = NULL; + for (i = 0; i < devcount; i++) { + if (pci_find_extcap(devlist[i], PCIZ_SRIOV, &iov_pos) == 0) { + dev_func = pci_get_function(devlist[i]); + if (lowest == NULL || dev_func < lowest_func) { + lowest = devlist[i]; + lowest_func = dev_func; + lowest_pos = iov_pos; + } + } + } + + /* + * If we called this function some device must have the SR-IOV + * capability. + */ + KASSERT(lowest != NULL, + ("Could not find child of %s with SR-IOV capability", + device_get_nameunit(bus))); + + iov_ctl = pci_read_config(lowest, iov_pos + PCIR_SRIOV_CTL, 2); + iov_ctl |= PCIM_SRIOV_ARI_EN; + pci_write_config(lowest, iov_pos + PCIR_SRIOV_CTL, iov_ctl, 2); + free(devlist, M_TEMP); + return (0); +} + +static int +pci_iov_config_page_size(struct pci_devinfo *dinfo) +{ + uint32_t page_cap, page_size; + + page_cap = IOV_READ(dinfo, PCIR_SRIOV_PAGE_CAP, 4); + + /* + * If the system page size is less than the smallest SR-IOV page size + * then round up to the smallest SR-IOV page size. + */ + if (PAGE_SHIFT < PCI_SRIOV_BASE_PAGE_SHIFT) + page_size = (1 << 0); + else + page_size = (1 << (PAGE_SHIFT - PCI_SRIOV_BASE_PAGE_SHIFT)); + + /* Check that the device supports the system page size. */ + if (!(page_size & page_cap)) + return (ENXIO); + + IOV_WRITE(dinfo, PCIR_SRIOV_PAGE_SIZE, page_size, 4); + return (0); +} + +static void +pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const char *driver, + uint16_t first_rid, uint16_t rid_stride) +{ + device_t bus, dev, vf; + struct pcicfg_iov *iov; + struct pci_devinfo *vfinfo; + int i, error; + uint16_t vid, did, next_rid; + + iov = dinfo->cfg.iov; + dev = dinfo->cfg.dev; + bus = device_get_parent(dev); + next_rid = first_rid; + vid = pci_get_vendor(dev); + did = IOV_READ(dinfo, PCIR_SRIOV_VF_DID, 2); + + for (i = 0; i < iov->iov_num_vfs; i++, next_rid += rid_stride) { + vf = pci_add_iov_child(bus, sizeof(*vfinfo), next_rid, vid, did, + driver); + + vfinfo = device_get_ivars(vf); + + vfinfo->cfg.iov = iov; + vfinfo->cfg.vf.index = i; + + error = PCI_ADD_VF(dev, i); + if (error != 0) { + device_printf(dev, "Failed to add VF %d\n", i); + pci_delete_child(bus, vf); + } + } + + bus_generic_attach(bus); +} + +static int +pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) +{ + device_t bus, dev; + const char *driver; + struct pci_devinfo *dinfo; + struct pcicfg_iov *iov; + int error; + uint16_t rid_off, rid_stride; + uint16_t first_rid, last_rid; + uint16_t iov_ctl; + uint16_t total_vfs; + int iov_inited; + + mtx_lock(&Giant); + dinfo = cdev->si_drv1; + iov = dinfo->cfg.iov; + dev = dinfo->cfg.dev; + bus = device_get_parent(dev); + iov_inited = 0; + + if (iov->iov_num_vfs != 0) { + mtx_unlock(&Giant); + return (EBUSY); + } + + total_vfs = IOV_READ(dinfo, PCIR_SRIOV_TOTAL_VFS, 2); + + if (arg->num_vfs > total_vfs) { + error = EINVAL; + goto out; + } + + /* + * If we are creating passthrough devices then force the ppt driver to + * attach to prevent a VF driver from claming the VFs. + */ + if (arg->passthrough) + driver = "ppt"; + else + driver = NULL; + + error = pci_iov_config_page_size(dinfo); + if (error != 0) + goto out; + + error = pci_iov_set_ari(bus); + if (error != 0) + goto out; + + error = PCI_INIT_IOV(dev, arg->num_vfs); + + if (error != 0) + goto out; + + iov_inited = 1; + IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, arg->num_vfs, 2); + + rid_off = IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, 2); + rid_stride = IOV_READ(dinfo, PCIR_SRIOV_VF_STRIDE, 2); + + first_rid = pci_get_rid(dev) + rid_off; + last_rid = first_rid + (arg->num_vfs - 1) * rid_stride; + + /* We don't yet support allocating extra bus numbers for VFs. */ + if (pci_get_bus(dev) != PCI_RID2BUS(last_rid)) { + error = ENOSPC; + goto out; + } + + iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); + iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE); + IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); + + iov->iov_num_vfs = arg->num_vfs; + + iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); + iov_ctl |= PCIM_SRIOV_VF_EN; + IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2); + + /* Per specification, we must wait 100ms before accessing VFs. */ + msleep(iov, &Giant, 0, "iov", hz/10); + pci_iov_enumerate_vfs(dinfo, driver, first_rid, rid_stride); + mtx_unlock(&Giant); + + return (0); +out: + if (iov_inited) + PCI_UNINIT_IOV(dev); + iov->iov_num_vfs = 0; + mtx_unlock(&Giant); + return (error); +} + +static int +pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + + switch (cmd) { + case IOV_CONFIG: + return (pci_iov_config(dev, (struct pci_iov_arg *)data)); + default: + return (EINVAL); + } +} + diff --git a/sys/dev/pci/pci_iov_private.h b/sys/dev/pci/pci_iov_private.h new file mode 100755 index 0000000..1c39dcb --- /dev/null +++ b/sys/dev/pci/pci_iov_private.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2013-2014 Sandvine Inc. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PCI_IOV_PRIVATE_H_ +#define _PCI_IOV_PRIVATE_H_ + +struct pcicfg_iov { + struct cdev *iov_cdev; + + int iov_pos; + int iov_num_vfs; +}; + +#endif + diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index a6d8cc8..4824180 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -143,4 +143,10 @@ struct resource *pci_alloc_multi_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_long num, u_int flags); +int pci_iov_attach_method(device_t bus, device_t dev); +int pci_iov_detach_method(device_t bus, device_t dev); + +device_t pci_add_iov_child(device_t bus, size_t size, uint16_t rid, + uint16_t vid, uint16_t did, const char *driver); + #endif /* _PCI_PRIVATE_H_ */ diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 788e4e6..d68cb25 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -924,3 +924,21 @@ #define PCIR_SERIAL_LOW 0x04 #define PCIR_SERIAL_HIGH 0x08 +/* SR-IOV definitions */ +#define PCIR_SRIOV_CTL 0x08 +#define PCIM_SRIOV_VF_EN 0x01 +#define PCIM_SRIOV_VF_MSE 0x08 /* Memory space enable. */ +#define PCIM_SRIOV_ARI_EN 0x10 +#define PCIR_SRIOV_TOTAL_VFS 0x0E +#define PCIR_SRIOV_NUM_VFS 0x10 +#define PCIR_SRIOV_VF_OFF 0x14 +#define PCIR_SRIOV_VF_STRIDE 0x16 +#define PCIR_SRIOV_VF_DID 0x1A +#define PCIR_SRIOV_PAGE_CAP 0x1C +#define PCIR_SRIOV_PAGE_SIZE 0x20 + +#define PCI_SRIOV_BASE_PAGE_SHIFT 12 + +#define PCIR_SRIOV_BARS 0x24 +#define PCIR_SRIOV_BAR(x) (PCIR_SRIOV_BARS + (x) * 4) + diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 0157ee7..0c90665 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -143,6 +143,12 @@ struct pcicfg_pcix { uint8_t pcix_location; /* Offset of PCI-X capability registers. */ }; +struct pcicfg_vf { + int index; +}; + +#define PCICFG_VF (1 << 0) /* Device is an SR-IOV Virtual Function */ + /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ @@ -179,6 +185,8 @@ typedef struct pcicfg { uint8_t slot; /* config space slot address */ uint8_t func; /* config space function number */ + uint32_t flags; /* flags defined above */ + struct pcicfg_pp pp; /* Power management */ struct pcicfg_vpd vpd; /* Vital product data */ struct pcicfg_msi msi; /* PCI MSI */ @@ -186,6 +194,8 @@ typedef struct pcicfg { struct pcicfg_ht ht; /* HyperTransport */ struct pcicfg_pcie pcie; /* PCI Express */ struct pcicfg_pcix pcix; /* PCI-X */ + struct pcicfg_iov *iov; /* SR-IOV */ + struct pcicfg_vf vf; /* SR-IOV Virtual Function */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ @@ -488,6 +498,18 @@ pci_get_rid(device_t dev) return (PCI_GET_RID(device_get_parent(dev), dev)); } +static __inline int +pci_iov_attach(device_t dev) +{ + return (PCI_IOV_ATTACH(device_get_parent(dev), dev)); +} + +static __inline int +pci_iov_detach(device_t dev) +{ + return (PCI_IOV_DETACH(device_get_parent(dev), dev)); +} + device_t pci_find_bsf(uint8_t, uint8_t, uint8_t); device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t); device_t pci_find_device(uint16_t, uint16_t); diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 62d1ace..03ef1f4 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -95,6 +95,7 @@ device cpufreq # Bus support. device acpi device pci +options PCI_IOV # PCI SR-IOV support # Floppy drives device fdc diff --git a/sys/sys/iov.h b/sys/sys/iov.h new file mode 100755 index 0000000..a77dcea --- /dev/null +++ b/sys/sys/iov.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2013 Sandvine Inc. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_IOV_H_ +#define _SYS_IOV_H_ + +#include + +struct pci_iov_arg +{ + int num_vfs; + int passthrough; +}; + +#define IOV_CONFIG _IOWR('p', 10, struct pci_iov_arg) + +#endif + -- 1.9.2