From 9bfb1e36d92d1650e4a121ad751dc2ffbfb4cecb Mon Sep 17 00:00:00 2001 From: Ryan Stone Date: Sun, 1 Mar 2015 00:40:09 +0000 Subject: [PATCH] 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. Differential Revision: https://reviews.freebsd.org/D76 Reviewed by: jhb MFC after: 1 month Sponsored by: Sandvine Inc. --- sys/amd64/conf/GENERIC | 1 + sys/conf/files | 1 + sys/conf/options | 1 + sys/dev/acpica/acpi_pci.c | 28 +++ sys/dev/pci/pci.c | 53 +++++ sys/dev/pci/pci_if.m | 41 ++++ sys/dev/pci/pci_iov.c | 385 ++++++++++++++++++++++++++++++++++ sys/dev/pci/pci_iov_private.h | 40 ++++ sys/dev/pci/pci_private.h | 8 + sys/dev/pci/pcireg.h | 18 ++ sys/dev/pci/pcivar.h | 23 ++ sys/i386/conf/GENERIC | 1 + sys/sys/iov.h | 43 ++++ 13 files changed, 643 insertions(+) create mode 100644 sys/dev/pci/pci_iov.c create mode 100644 sys/dev/pci/pci_iov_private.h create mode 100644 sys/sys/iov.h diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 86891b7507f9..dff36aceffb9 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -97,6 +97,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 3e368ab0cd43..799e438f011a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2031,6 +2031,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 08a5523e2d31..2d6d54b2e24e 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -173,6 +173,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/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c index 3d072055b25e..9509f82313a1 100644 --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -84,6 +84,11 @@ static int acpi_pci_set_powerstate_method(device_t dev, device_t child, static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child); static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child); +#ifdef PCI_IOV +static device_t acpi_pci_create_iov_child(device_t bus, device_t pf, + uint16_t rid, uint16_t vid, uint16_t did); +#endif + static device_method_t acpi_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_pci_probe), @@ -98,6 +103,9 @@ static device_method_t acpi_pci_methods[] = { /* PCI interface */ DEVMETHOD(pci_set_powerstate, acpi_pci_set_powerstate_method), +#ifdef PCI_IOV + DEVMETHOD(pci_create_iov_child, acpi_pci_create_iov_child), +#endif DEVMETHOD_END }; @@ -345,3 +353,23 @@ acpi_pci_get_dma_tag(device_t bus, device_t child) return (pci_get_dma_tag(bus, child)); } #endif + +#ifdef PCI_IOV +static device_t +acpi_pci_create_iov_child(device_t bus, device_t pf, uint16_t rid, uint16_t vid, + uint16_t did) +{ + struct acpi_pci_devinfo *dinfo; + device_t vf; + + vf = pci_add_iov_child(bus, pf, sizeof(struct acpi_pci_devinfo), rid, + vid, did); + if (vf == NULL) + return (NULL); + + dinfo = device_get_ivars(vf); + dinfo->ap_handle = NULL; + return (vf); +} +#endif + diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 5cf51933750d..517e91e18618 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -189,6 +189,11 @@ static device_method_t pci_methods[] = { DEVMETHOD(pci_msix_count, pci_msix_count_method), DEVMETHOD(pci_get_rid, pci_get_rid_method), DEVMETHOD(pci_child_added, pci_child_added_method), +#ifdef PCI_IOV + DEVMETHOD(pci_iov_attach, pci_iov_attach_method), + DEVMETHOD(pci_iov_detach, pci_iov_detach_method), + DEVMETHOD(pci_create_iov_child, pci_create_iov_child_method), +#endif DEVMETHOD_END }; @@ -643,6 +648,9 @@ 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->devinfo_size = size; + cfg->iov = NULL; + pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); @@ -3546,6 +3554,51 @@ 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, device_t pf, size_t size, uint16_t rid, + uint16_t vid, uint16_t did) +{ + struct pci_devinfo *pf_dinfo, *vf_dinfo; + device_t pcib; + int busno, slot, func; + + pf_dinfo = device_get_ivars(pf); + + /* + * Do a sanity check that we have been passed the correct size. If this + * test fails then likely the pci subclass hasn't implemented the + * pci_create_iov_child method like it's supposed it. + */ + if (size != pf_dinfo->cfg.devinfo_size) { + device_printf(pf, + "PCI subclass does not properly implement PCI_IOV\n"); + return (NULL); + } + + pcib = device_get_parent(bus); + + PCIB_DECODE_RID(pcib, rid, &busno, &slot, &func); + + vf_dinfo = pci_fill_devinfo(pcib, pci_get_domain(pcib), busno, slot, func, + vid, did, size); + + vf_dinfo->cfg.flags |= PCICFG_VF; + pci_add_child(bus, vf_dinfo); + + return (vf_dinfo->cfg.dev); +} + +device_t +pci_create_iov_child_method(device_t bus, device_t pf, uint16_t rid, + uint16_t vid, uint16_t did) +{ + + return (pci_add_iov_child(bus, pf, sizeof(struct pci_devinfo), rid, vid, + did)); +} +#endif + void pci_add_child(device_t bus, struct pci_devinfo *dinfo) { diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m index 227d3620ae80..0c4f8738cd57 100644 --- a/sys/dev/pci/pci_if.m +++ b/sys/dev/pci/pci_if.m @@ -36,6 +36,14 @@ CODE { { return (0); } + + static device_t + null_create_iov_child(device_t bus, device_t pf, uint16_t rid, + uint16_t vid, uint16_t did) + { + device_printf(bus, "PCI_IOV not implemented on this bus.\n"); + return (NULL); + } }; @@ -189,3 +197,36 @@ METHOD void child_added { device_t dev; 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; +}; + +METHOD device_t create_iov_child { + device_t bus; + device_t pf; + uint16_t rid; + uint16_t vid; + uint16_t did; +} DEFAULT null_create_iov_child; + diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c new file mode 100644 index 000000000000..f710c4b9f8d5 --- /dev/null +++ b/sys/dev/pci/pci_iov.c @@ -0,0 +1,385 @@ +/*- + * Copyright (c) 2013-2015 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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; + size_t size; + int i, error; + uint16_t vid, did, next_rid; + + iov = dinfo->cfg.iov; + dev = dinfo->cfg.dev; + bus = device_get_parent(dev); + size = dinfo->cfg.devinfo_size; + 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_CREATE_IOV_CHILD(bus, dev, next_rid, vid, did); + if (vf == NULL) + break; + + 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. */ + pause("iov", roundup(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 100644 index 000000000000..74a4279b6a6b --- /dev/null +++ b/sys/dev/pci/pci_iov_private.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2013-2015 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 5f1ebf0eed0e..bf89ef367788 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -51,6 +51,8 @@ extern int pci_do_power_suspend; void pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size); void pci_add_child(device_t bus, struct pci_devinfo *dinfo); +device_t pci_add_iov_child(device_t bus, device_t pf, size_t dinfo_size, + uint16_t rid, uint16_t vid, uint16_t did); void pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask); int pci_attach_common(device_t dev); @@ -150,4 +152,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_create_iov_child_method(device_t bus, device_t pf, + uint16_t rid, uint16_t vid, uint16_t did); + #endif /* _PCI_PRIVATE_H_ */ diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 788e4e676799..d68cb257a3fd 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 89407a7543cc..c433940ffb27 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 0x0001 /* 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,9 @@ typedef struct pcicfg { uint8_t slot; /* config space slot address */ uint8_t func; /* config space function number */ + uint32_t flags; /* flags defined above */ + size_t devinfo_size; /* Size of devinfo for this bus type. */ + struct pcicfg_pp pp; /* Power management */ struct pcicfg_vpd vpd; /* Vital product data */ struct pcicfg_msi msi; /* PCI MSI */ @@ -186,6 +195,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) */ @@ -513,6 +524,18 @@ pci_child_added(device_t dev) return (PCI_CHILD_ADDED(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 29d56da1b2d7..086844a87ea1 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -97,6 +97,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 100644 index 000000000000..bb5c0696f4d8 --- /dev/null +++ b/sys/sys/iov.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2013-2015 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, 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +