/** * pci_iov_get_pf_drvdata - Return the drvdata of a PF * @dev: VF pci_dev * @pf_driver: Device driver required to own the PF * * This must be called from a context that ensures that a VF driver is attached. * The value returned is invalid once the VF driver completes its remove() * callback. * * Locking is achieved by the driver core. A VF driver cannot be probed until * pci_enable_sriov() is called and pci_disable_sriov() does not return until * all VF drivers have completed their remove(). * * The PF driver must call pci_disable_sriov() before it begins to destroy the * drvdata.
*/ void *pci_iov_get_pf_drvdata(struct pci_dev *dev, struct pci_driver *pf_driver)
{ struct pci_dev *pf_dev;
if (!dev->is_virtfn) return ERR_PTR(-EINVAL);
pf_dev = dev->physfn; if (pf_dev->driver != pf_driver) return ERR_PTR(-EINVAL); return pci_get_drvdata(pf_dev);
}
EXPORT_SYMBOL_GPL(pci_iov_get_pf_drvdata);
/* * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may * change when NumVFs changes. * * Update iov->offset and iov->stride when NumVFs is written.
*/ staticinlinevoid pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn)
{ struct pci_sriov *iov = dev->sriov;
/* * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride * determine how many additional bus numbers will be consumed by VFs. * * Iterate over all valid NumVFs, validate offset and stride, and calculate * the maximum number of bus numbers that could ever be required.
*/ staticint compute_max_vf_buses(struct pci_dev *dev)
{ struct pci_sriov *iov = dev->sriov; int nr_virtfn, busnr, rc = 0;
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
resource_size_t size)
{ if (!pci_resource_is_iov(resno)) {
pci_warn(dev, "%s is not an IOV resource\n",
pci_resource_name(dev, resno)); return;
}
/* * Some config registers are the same across all associated VFs. * Read them once from VF0 so we can skip reading them from the * other VFs. * * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to * have the same Revision ID and Subsystem ID, but we assume they * do.
*/
pci_read_config_dword(virtfn, PCI_CLASS_REVISION,
&physfn->sriov->class);
pci_read_config_byte(virtfn, PCI_HEADER_TYPE,
&physfn->sriov->hdr_type);
pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID,
&physfn->sriov->subsystem_vendor);
pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
&physfn->sriov->subsystem_device);
}
int pci_iov_sysfs_link(struct pci_dev *dev, struct pci_dev *virtfn, int id)
{ char buf[VIRTFN_ID_LEN]; int rc;
device_lock(&pdev->dev); if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) {
ret = -EOPNOTSUPP; goto err_pdev;
}
device_lock(&vf_dev->dev); if (vf_dev->driver) { /* * A driver is already attached to this VF and has configured * itself based on the current MSI-X vector count. Changing * the vector size could mess up the driver, so block it.
*/
ret = -EBUSY; goto err_dev;
}
ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val);
virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
pci_iov_virtfn_bus(dev, id),
pci_iov_virtfn_devfn(dev, id)); if (!virtfn) return;
sprintf(buf, "virtfn%u", id);
sysfs_remove_link(&dev->dev.kobj, buf); /* * pci_stop_dev() could have been called for this virtfn already, * so the directory for the virtfn may have been removed before. * Double check to avoid spurious sysfs warnings.
*/ if (virtfn->dev.kobj.sd)
sysfs_remove_link(&virtfn->dev.kobj, "physfn");
/* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */
device_lock(&pdev->dev);
num_vfs = pdev->sriov->num_VFs;
device_unlock(&pdev->dev);
return sysfs_emit(buf, "%u\n", num_vfs);
}
/* * num_vfs > 0; number of VFs to enable * num_vfs = 0; disable all VFs * * Note: SRIOV spec does not allow partial VF * disable, so it's all or none.
*/ static ssize_t sriov_numvfs_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct pci_dev *pdev = to_pci_dev(dev); int ret = 0;
u16 num_vfs;
if (kstrtou16(buf, 0, &num_vfs) < 0) return -EINVAL;
if (num_vfs > pci_sriov_get_totalvfs(pdev)) return -ERANGE;
device_lock(&pdev->dev);
if (num_vfs == pdev->sriov->num_VFs) gotoexit;
/* is PF driver loaded */ if (!pdev->driver) {
pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n");
ret = -ENOENT; gotoexit;
}
/* is PF driver loaded w/callback */ if (!pdev->driver->sriov_configure) {
pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n");
ret = -ENOENT; gotoexit;
}
if (num_vfs == 0) { /* disable VFs */
ret = pdev->driver->sriov_configure(pdev, 0); gotoexit;
}
/* enable VFs */ if (pdev->sriov->num_VFs) {
pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n",
pdev->sriov->num_VFs, num_vfs);
ret = -EBUSY; gotoexit;
}
ret = pdev->driver->sriov_configure(pdev, num_vfs); if (ret < 0) gotoexit;
if (ret != num_vfs)
pci_warn(pdev, "%d VFs requested; only %d enabled\n",
num_vfs, ret);
nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { int idx = pci_resource_num_from_vf_bar(i);
resource_size_t vf_bar_sz = pci_iov_resource_size(dev, idx);
bars |= (1 << idx);
res = &dev->resource[idx]; if (vf_bar_sz * nr_virtfn > resource_size(res)) continue; if (res->parent)
nres++;
} if (nres != iov->nres) {
pci_err(dev, "not enough MMIO resources for SR-IOV\n"); return -ENOMEM;
}
bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1); if (bus > dev->bus->busn_res.end) {
pci_err(dev, "can't enable %d VFs (bus %02x out of range of %pR)\n",
nr_virtfn, bus, &dev->bus->busn_res); return -ENOMEM;
}
if (pci_enable_resources(dev, bars)) {
pci_err(dev, "SR-IOV: IOV BARS not allocated\n"); return -ENOMEM;
}
if (iov->link != dev->devfn) {
pdev = pci_get_slot(dev->bus, iov->link); if (!pdev) return -ENODEV;
if (!pdev->is_physfn) {
pci_dev_put(pdev); return -ENOSYS;
}
/** * pci_iov_init - initialize the IOV capability * @dev: the PCI device * * Returns 0 on success, or negative on failure.
*/ int pci_iov_init(struct pci_dev *dev)
{ int pos;
if (!pci_is_pcie(dev)) return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); if (pos) return sriov_init(dev, pos);
return -ENODEV;
}
/** * pci_iov_release - release resources used by the IOV capability * @dev: the PCI device
*/ void pci_iov_release(struct pci_dev *dev)
{ if (dev->is_physfn)
sriov_release(dev);
}
/** * pci_iov_remove - clean up SR-IOV state after PF driver is detached * @dev: the PCI device
*/ void pci_iov_remove(struct pci_dev *dev)
{ struct pci_sriov *iov = dev->sriov;
if (!dev->is_physfn) return;
iov->driver_max_VFs = iov->total_VFs; if (iov->num_VFs)
pci_warn(dev, "driver left SR-IOV enabled after remove\n");
}
/** * pci_iov_update_resource - update a VF BAR * @dev: the PCI device * @resno: the resource number * * Update a VF BAR in the SR-IOV capability of a PF.
*/ void pci_iov_update_resource(struct pci_dev *dev, int resno)
{ struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; struct resource *res = pci_resource_n(dev, resno); int vf_bar = pci_resource_num_to_vf_bar(resno); struct pci_bus_region region;
u16 cmd;
u32 new; int reg;
/* * The generic pci_restore_bars() path calls this for all devices, * including VFs and non-SR-IOV devices. If this is not a PF, we * have nothing to do.
*/ if (!iov) return;
/* * Ignore unimplemented BARs, unused resource slots for 64-bit * BARs, and non-movable resources, e.g., those described via * Enhanced Allocation.
*/ if (!res->flags) return;
if (res->flags & IORESOURCE_UNSET) return;
if (res->flags & IORESOURCE_PCI_FIXED) return;
pcibios_resource_to_bus(dev->bus, ®ion, res); new = region.start; new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
/** * pci_sriov_resource_alignment - get resource alignment for VF BAR * @dev: the PCI device * @resno: the resource number * * Returns the alignment of the VF BAR found in the SR-IOV capability. * This is not the same as the resource size which is defined as * the VF BAR size multiplied by the number of VFs. The alignment * is just the VF BAR size.
*/
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
{ return pcibios_iov_resource_alignment(dev, resno);
}
/** * pci_restore_iov_state - restore the state of the IOV capability * @dev: the PCI device
*/ void pci_restore_iov_state(struct pci_dev *dev)
{ if (dev->is_physfn) {
sriov_restore_vf_rebar_state(dev);
sriov_restore_state(dev);
}
}
/** * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs * @dev: the PCI device * @auto_probe: set VF drivers auto probe flag
*/ void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe)
{ if (dev->is_physfn)
dev->sriov->drivers_autoprobe = auto_probe;
}
/** * pci_iov_bus_range - find bus range used by Virtual Function * @bus: the PCI bus * * Returns max number of buses (exclude current one) used by Virtual * Functions.
*/ int pci_iov_bus_range(struct pci_bus *bus)
{ int max = 0; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { if (!dev->is_physfn) continue; if (dev->sriov->max_VF_buses > max)
max = dev->sriov->max_VF_buses;
}
return max ? max - bus->number : 0;
}
/** * pci_enable_sriov - enable the SR-IOV capability * @dev: the PCI device * @nr_virtfn: number of virtual functions to enable * * Returns 0 on success, or negative on failure.
*/ int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
{
might_sleep();
/** * pci_num_vf - return number of VFs associated with a PF device_release_driver * @dev: the PCI device * * Returns number of VFs, or 0 if SR-IOV is not enabled.
*/ int pci_num_vf(struct pci_dev *dev)
{ if (!dev->is_physfn) return 0;
/** * pci_vfs_assigned - returns number of VFs are assigned to a guest * @dev: the PCI device * * Returns number of VFs belonging to this device that are assigned to a guest. * If device is not a physical function returns 0.
*/ int pci_vfs_assigned(struct pci_dev *dev)
{ struct pci_dev *vfdev; unsignedint vfs_assigned = 0; unsignedshort dev_id;
/* only search if we are a PF */ if (!dev->is_physfn) return 0;
/* * determine the device ID for the VFs, the vendor ID will be the * same as the PF so there is no need to check for that one
*/
dev_id = dev->sriov->vf_device;
/* loop through all the VFs to see if we own any that are assigned */
vfdev = pci_get_device(dev->vendor, dev_id, NULL); while (vfdev) { /* * It is considered assigned if it is a virtual function with * our dev as the physical function and the assigned bit is set
*/ if (vfdev->is_virtfn && (vfdev->physfn == dev) &&
pci_is_dev_assigned(vfdev))
vfs_assigned++;
/** * pci_sriov_set_totalvfs -- reduce the TotalVFs available * @dev: the PCI PF device * @numvfs: number that should be used for TotalVFs supported * * Should be called from PF driver's probe routine with * device's mutex held. * * Returns 0 if PF is an SRIOV-capable device and * value of numvfs valid. If not a PF return -ENOSYS; * if numvfs is invalid return -EINVAL; * if VFs already enabled, return -EBUSY.
*/ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
{ if (!dev->is_physfn) return -ENOSYS;
if (numvfs > dev->sriov->total_VFs) return -EINVAL;
/* Shouldn't change if VFs already enabled */ if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) return -EBUSY;
/** * pci_sriov_get_totalvfs -- get total VFs supported on this device * @dev: the PCI PF device * * For a PCIe device with SRIOV support, return the PCIe * SRIOV capability value of TotalVFs or the value of driver_max_VFs * if the driver reduced it. Otherwise 0.
*/ int pci_sriov_get_totalvfs(struct pci_dev *dev)
{ if (!dev->is_physfn) return 0;
/** * pci_sriov_configure_simple - helper to configure SR-IOV * @dev: the PCI device * @nr_virtfn: number of virtual functions to enable, 0 to disable * * Enable or disable SR-IOV for devices that don't require any PF setup * before enabling SR-IOV. Return value is negative on error, or number of * VFs allocated on success.
*/ int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
{ int rc;
might_sleep();
if (!dev->is_physfn) return -ENODEV;
if (pci_vfs_assigned(dev)) {
pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n"); return -EPERM;
}
if (nr_virtfn == 0) {
sriov_disable(dev); return 0;
}
rc = sriov_enable(dev, nr_virtfn); if (rc < 0) return rc;
/** * pci_iov_vf_bar_set_size - set a new size for a VF BAR * @dev: the PCI device * @resno: the resource number * @size: new size as defined in the spec (0=1MB, 31=128TB) * * Set the new size of a VF BAR that supports VF resizable BAR capability. * Unlike pci_resize_resource(), this does not cause the resource that * reserves the MMIO space (originally up to total_VFs) to be resized, which * means that following calls to pci_enable_sriov() can fail if the resources * no longer fit. * * Return: 0 on success, or negative on failure.
*/ int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
{
u32 sizes; int ret;
if (!pci_resource_is_iov(resno)) return -EINVAL;
if (pci_iov_is_memory_decoding_enabled(dev)) return -EBUSY;
sizes = pci_rebar_get_possible_sizes(dev, resno); if (!sizes) return -ENOTSUPP;
if (!(sizes & BIT(size))) return -EINVAL;
ret = pci_rebar_set_size(dev, resno, size); if (ret) return ret;
/** * pci_iov_vf_bar_get_sizes - get VF BAR sizes allowing to create up to num_vfs * @dev: the PCI device * @resno: the resource number * @num_vfs: number of VFs * * Get the sizes of a VF resizable BAR that can accommodate @num_vfs within * the currently assigned size of the resource @resno. * * Return: A bitmask of sizes in format defined in the spec (bit 0=1MB, * bit 31=128TB).
*/
u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
{
u64 vf_len = pci_resource_len(dev, resno);
u32 sizes;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.