17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0 2d1b054daSYu Zhao /* 3df62ab5eSBjorn Helgaas * PCI Express I/O Virtualization (IOV) support 4d1b054daSYu Zhao * Single Root IOV 1.0 5302b4215SYu Zhao * Address Translation Service 1.0 6df62ab5eSBjorn Helgaas * 7df62ab5eSBjorn Helgaas * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com> 8d1b054daSYu Zhao */ 9d1b054daSYu Zhao 10d1b054daSYu Zhao #include <linux/pci.h> 115a0e3ad6STejun Heo #include <linux/slab.h> 12363c75dbSPaul Gortmaker #include <linux/export.h> 13d1b054daSYu Zhao #include <linux/string.h> 14d1b054daSYu Zhao #include <linux/delay.h> 15d1b054daSYu Zhao #include "pci.h" 16d1b054daSYu Zhao 17*ea0b5aa5SAlexey V. Vissarionov #define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */ 18d1b054daSYu Zhao 19b07579c0SWei Yang int pci_iov_virtfn_bus(struct pci_dev *dev, int vf_id) 20a28724b0SYu Zhao { 21b07579c0SWei Yang if (!dev->is_physfn) 22b07579c0SWei Yang return -EINVAL; 23a28724b0SYu Zhao return dev->bus->number + ((dev->devfn + dev->sriov->offset + 24b07579c0SWei Yang dev->sriov->stride * vf_id) >> 8); 25a28724b0SYu Zhao } 26a28724b0SYu Zhao 27b07579c0SWei Yang int pci_iov_virtfn_devfn(struct pci_dev *dev, int vf_id) 28a28724b0SYu Zhao { 29b07579c0SWei Yang if (!dev->is_physfn) 30b07579c0SWei Yang return -EINVAL; 31a28724b0SYu Zhao return (dev->devfn + dev->sriov->offset + 32b07579c0SWei Yang dev->sriov->stride * vf_id) & 0xff; 33a28724b0SYu Zhao } 34c3d5c2d9SLeon Romanovsky EXPORT_SYMBOL_GPL(pci_iov_virtfn_devfn); 35a28724b0SYu Zhao 3621ca9fb6SJason Gunthorpe int pci_iov_vf_id(struct pci_dev *dev) 3721ca9fb6SJason Gunthorpe { 3821ca9fb6SJason Gunthorpe struct pci_dev *pf; 3921ca9fb6SJason Gunthorpe 4021ca9fb6SJason Gunthorpe if (!dev->is_virtfn) 4121ca9fb6SJason Gunthorpe return -EINVAL; 4221ca9fb6SJason Gunthorpe 4321ca9fb6SJason Gunthorpe pf = pci_physfn(dev); 4421ca9fb6SJason Gunthorpe return (((dev->bus->number << 8) + dev->devfn) - 4521ca9fb6SJason Gunthorpe ((pf->bus->number << 8) + pf->devfn + pf->sriov->offset)) / 4621ca9fb6SJason Gunthorpe pf->sriov->stride; 4721ca9fb6SJason Gunthorpe } 4821ca9fb6SJason Gunthorpe EXPORT_SYMBOL_GPL(pci_iov_vf_id); 4921ca9fb6SJason Gunthorpe 50a7e9f240SJason Gunthorpe /** 51a7e9f240SJason Gunthorpe * pci_iov_get_pf_drvdata - Return the drvdata of a PF 528d26c432SLeon Romanovsky * @dev: VF pci_dev 538d26c432SLeon Romanovsky * @pf_driver: Device driver required to own the PF 54a7e9f240SJason Gunthorpe * 55a7e9f240SJason Gunthorpe * This must be called from a context that ensures that a VF driver is attached. 56a7e9f240SJason Gunthorpe * The value returned is invalid once the VF driver completes its remove() 57a7e9f240SJason Gunthorpe * callback. 58a7e9f240SJason Gunthorpe * 59a7e9f240SJason Gunthorpe * Locking is achieved by the driver core. A VF driver cannot be probed until 60a7e9f240SJason Gunthorpe * pci_enable_sriov() is called and pci_disable_sriov() does not return until 61a7e9f240SJason Gunthorpe * all VF drivers have completed their remove(). 62a7e9f240SJason Gunthorpe * 63a7e9f240SJason Gunthorpe * The PF driver must call pci_disable_sriov() before it begins to destroy the 64a7e9f240SJason Gunthorpe * drvdata. 65a7e9f240SJason Gunthorpe */ 66a7e9f240SJason Gunthorpe void *pci_iov_get_pf_drvdata(struct pci_dev *dev, struct pci_driver *pf_driver) 67a7e9f240SJason Gunthorpe { 68a7e9f240SJason Gunthorpe struct pci_dev *pf_dev; 69a7e9f240SJason Gunthorpe 70a7e9f240SJason Gunthorpe if (!dev->is_virtfn) 71a7e9f240SJason Gunthorpe return ERR_PTR(-EINVAL); 72a7e9f240SJason Gunthorpe pf_dev = dev->physfn; 73a7e9f240SJason Gunthorpe if (pf_dev->driver != pf_driver) 74a7e9f240SJason Gunthorpe return ERR_PTR(-EINVAL); 75a7e9f240SJason Gunthorpe return pci_get_drvdata(pf_dev); 76a7e9f240SJason Gunthorpe } 77a7e9f240SJason Gunthorpe EXPORT_SYMBOL_GPL(pci_iov_get_pf_drvdata); 78a7e9f240SJason Gunthorpe 79f59dca27SWei Yang /* 80f59dca27SWei Yang * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may 81f59dca27SWei Yang * change when NumVFs changes. 82f59dca27SWei Yang * 83f59dca27SWei Yang * Update iov->offset and iov->stride when NumVFs is written. 84f59dca27SWei Yang */ 85f59dca27SWei Yang static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn) 86f59dca27SWei Yang { 87f59dca27SWei Yang struct pci_sriov *iov = dev->sriov; 88f59dca27SWei Yang 89f59dca27SWei Yang pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); 90f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 91f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 92f59dca27SWei Yang } 93f59dca27SWei Yang 944449f079SWei Yang /* 954449f079SWei Yang * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride 964449f079SWei Yang * determine how many additional bus numbers will be consumed by VFs. 974449f079SWei Yang * 98ea9a8854SAlexander Duyck * Iterate over all valid NumVFs, validate offset and stride, and calculate 99ea9a8854SAlexander Duyck * the maximum number of bus numbers that could ever be required. 1004449f079SWei Yang */ 101ea9a8854SAlexander Duyck static int compute_max_vf_buses(struct pci_dev *dev) 1024449f079SWei Yang { 1034449f079SWei Yang struct pci_sriov *iov = dev->sriov; 104ea9a8854SAlexander Duyck int nr_virtfn, busnr, rc = 0; 1054449f079SWei Yang 106ea9a8854SAlexander Duyck for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) { 1074449f079SWei Yang pci_iov_set_numvfs(dev, nr_virtfn); 108ea9a8854SAlexander Duyck if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) { 109ea9a8854SAlexander Duyck rc = -EIO; 110ea9a8854SAlexander Duyck goto out; 1114449f079SWei Yang } 1124449f079SWei Yang 113ea9a8854SAlexander Duyck busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 114ea9a8854SAlexander Duyck if (busnr > iov->max_VF_buses) 115ea9a8854SAlexander Duyck iov->max_VF_buses = busnr; 116ea9a8854SAlexander Duyck } 117ea9a8854SAlexander Duyck 118ea9a8854SAlexander Duyck out: 119ea9a8854SAlexander Duyck pci_iov_set_numvfs(dev, 0); 120ea9a8854SAlexander Duyck return rc; 1214449f079SWei Yang } 1224449f079SWei Yang 123dd7cc44dSYu Zhao static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) 124dd7cc44dSYu Zhao { 125dd7cc44dSYu Zhao struct pci_bus *child; 126dd7cc44dSYu Zhao 127dd7cc44dSYu Zhao if (bus->number == busnr) 128dd7cc44dSYu Zhao return bus; 129dd7cc44dSYu Zhao 130dd7cc44dSYu Zhao child = pci_find_bus(pci_domain_nr(bus), busnr); 131dd7cc44dSYu Zhao if (child) 132dd7cc44dSYu Zhao return child; 133dd7cc44dSYu Zhao 134dd7cc44dSYu Zhao child = pci_add_new_bus(bus, NULL, busnr); 135dd7cc44dSYu Zhao if (!child) 136dd7cc44dSYu Zhao return NULL; 137dd7cc44dSYu Zhao 138b7eac055SYinghai Lu pci_bus_insert_busn_res(child, busnr, busnr); 139dd7cc44dSYu Zhao 140dd7cc44dSYu Zhao return child; 141dd7cc44dSYu Zhao } 142dd7cc44dSYu Zhao 143dc087f2fSJiang Liu static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus) 144dd7cc44dSYu Zhao { 145dc087f2fSJiang Liu if (physbus != virtbus && list_empty(&virtbus->devices)) 146dc087f2fSJiang Liu pci_remove_bus(virtbus); 147dd7cc44dSYu Zhao } 148dd7cc44dSYu Zhao 1490e6c9122SWei Yang resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) 1500e6c9122SWei Yang { 1510e6c9122SWei Yang if (!dev->is_physfn) 1520e6c9122SWei Yang return 0; 1530e6c9122SWei Yang 1540e6c9122SWei Yang return dev->sriov->barsz[resno - PCI_IOV_RESOURCES]; 1550e6c9122SWei Yang } 1560e6c9122SWei Yang 157cf0921beSKarimAllah Ahmed static void pci_read_vf_config_common(struct pci_dev *virtfn) 158cf0921beSKarimAllah Ahmed { 159cf0921beSKarimAllah Ahmed struct pci_dev *physfn = virtfn->physfn; 160cf0921beSKarimAllah Ahmed 161cf0921beSKarimAllah Ahmed /* 162cf0921beSKarimAllah Ahmed * Some config registers are the same across all associated VFs. 163cf0921beSKarimAllah Ahmed * Read them once from VF0 so we can skip reading them from the 164cf0921beSKarimAllah Ahmed * other VFs. 165cf0921beSKarimAllah Ahmed * 166cf0921beSKarimAllah Ahmed * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to 167cf0921beSKarimAllah Ahmed * have the same Revision ID and Subsystem ID, but we assume they 168cf0921beSKarimAllah Ahmed * do. 169cf0921beSKarimAllah Ahmed */ 170cf0921beSKarimAllah Ahmed pci_read_config_dword(virtfn, PCI_CLASS_REVISION, 171cf0921beSKarimAllah Ahmed &physfn->sriov->class); 172cf0921beSKarimAllah Ahmed pci_read_config_byte(virtfn, PCI_HEADER_TYPE, 173cf0921beSKarimAllah Ahmed &physfn->sriov->hdr_type); 174cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID, 175cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_vendor); 176cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID, 177cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_device); 178cf0921beSKarimAllah Ahmed } 179cf0921beSKarimAllah Ahmed 180a1ceea67SNiklas Schnelle int pci_iov_sysfs_link(struct pci_dev *dev, 181a1ceea67SNiklas Schnelle struct pci_dev *virtfn, int id) 182a1ceea67SNiklas Schnelle { 183a1ceea67SNiklas Schnelle char buf[VIRTFN_ID_LEN]; 184a1ceea67SNiklas Schnelle int rc; 185a1ceea67SNiklas Schnelle 186a1ceea67SNiklas Schnelle sprintf(buf, "virtfn%u", id); 187a1ceea67SNiklas Schnelle rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); 188a1ceea67SNiklas Schnelle if (rc) 189a1ceea67SNiklas Schnelle goto failed; 190a1ceea67SNiklas Schnelle rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn"); 191a1ceea67SNiklas Schnelle if (rc) 192a1ceea67SNiklas Schnelle goto failed1; 193a1ceea67SNiklas Schnelle 194a1ceea67SNiklas Schnelle kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); 195a1ceea67SNiklas Schnelle 196a1ceea67SNiklas Schnelle return 0; 197a1ceea67SNiklas Schnelle 198a1ceea67SNiklas Schnelle failed1: 199a1ceea67SNiklas Schnelle sysfs_remove_link(&dev->dev.kobj, buf); 200a1ceea67SNiklas Schnelle failed: 201a1ceea67SNiklas Schnelle return rc; 202a1ceea67SNiklas Schnelle } 203a1ceea67SNiklas Schnelle 204c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 205c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_total_msix_show(struct device *dev, 206c3d5c2d9SLeon Romanovsky struct device_attribute *attr, 207c3d5c2d9SLeon Romanovsky char *buf) 208c3d5c2d9SLeon Romanovsky { 209c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev); 210c3d5c2d9SLeon Romanovsky u32 vf_total_msix = 0; 211c3d5c2d9SLeon Romanovsky 212c3d5c2d9SLeon Romanovsky device_lock(dev); 213e0217c5bSBjorn Helgaas if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix) 214c3d5c2d9SLeon Romanovsky goto unlock; 215c3d5c2d9SLeon Romanovsky 216e0217c5bSBjorn Helgaas vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev); 217c3d5c2d9SLeon Romanovsky unlock: 218c3d5c2d9SLeon Romanovsky device_unlock(dev); 219c3d5c2d9SLeon Romanovsky return sysfs_emit(buf, "%u\n", vf_total_msix); 220c3d5c2d9SLeon Romanovsky } 221c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_RO(sriov_vf_total_msix); 222c3d5c2d9SLeon Romanovsky 223c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_msix_count_store(struct device *dev, 224c3d5c2d9SLeon Romanovsky struct device_attribute *attr, 225c3d5c2d9SLeon Romanovsky const char *buf, size_t count) 226c3d5c2d9SLeon Romanovsky { 227c3d5c2d9SLeon Romanovsky struct pci_dev *vf_dev = to_pci_dev(dev); 228c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = pci_physfn(vf_dev); 22936f354ecSKrzysztof Wilczyński int val, ret = 0; 230c3d5c2d9SLeon Romanovsky 23136f354ecSKrzysztof Wilczyński if (kstrtoint(buf, 0, &val) < 0) 23236f354ecSKrzysztof Wilczyński return -EINVAL; 233c3d5c2d9SLeon Romanovsky 234c3d5c2d9SLeon Romanovsky if (val < 0) 235c3d5c2d9SLeon Romanovsky return -EINVAL; 236c3d5c2d9SLeon Romanovsky 237c3d5c2d9SLeon Romanovsky device_lock(&pdev->dev); 238e0217c5bSBjorn Helgaas if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) { 239c3d5c2d9SLeon Romanovsky ret = -EOPNOTSUPP; 240c3d5c2d9SLeon Romanovsky goto err_pdev; 241c3d5c2d9SLeon Romanovsky } 242c3d5c2d9SLeon Romanovsky 243c3d5c2d9SLeon Romanovsky device_lock(&vf_dev->dev); 244e0217c5bSBjorn Helgaas if (vf_dev->driver) { 245c3d5c2d9SLeon Romanovsky /* 246c3d5c2d9SLeon Romanovsky * A driver is already attached to this VF and has configured 247c3d5c2d9SLeon Romanovsky * itself based on the current MSI-X vector count. Changing 248c3d5c2d9SLeon Romanovsky * the vector size could mess up the driver, so block it. 249c3d5c2d9SLeon Romanovsky */ 250c3d5c2d9SLeon Romanovsky ret = -EBUSY; 251c3d5c2d9SLeon Romanovsky goto err_dev; 252c3d5c2d9SLeon Romanovsky } 253c3d5c2d9SLeon Romanovsky 254e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val); 255c3d5c2d9SLeon Romanovsky 256c3d5c2d9SLeon Romanovsky err_dev: 257c3d5c2d9SLeon Romanovsky device_unlock(&vf_dev->dev); 258c3d5c2d9SLeon Romanovsky err_pdev: 259c3d5c2d9SLeon Romanovsky device_unlock(&pdev->dev); 260c3d5c2d9SLeon Romanovsky return ret ? : count; 261c3d5c2d9SLeon Romanovsky } 262c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_WO(sriov_vf_msix_count); 263c3d5c2d9SLeon Romanovsky #endif 264c3d5c2d9SLeon Romanovsky 265c3d5c2d9SLeon Romanovsky static struct attribute *sriov_vf_dev_attrs[] = { 266c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 267c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_msix_count.attr, 268c3d5c2d9SLeon Romanovsky #endif 269c3d5c2d9SLeon Romanovsky NULL, 270c3d5c2d9SLeon Romanovsky }; 271c3d5c2d9SLeon Romanovsky 272c3d5c2d9SLeon Romanovsky static umode_t sriov_vf_attrs_are_visible(struct kobject *kobj, 273c3d5c2d9SLeon Romanovsky struct attribute *a, int n) 274c3d5c2d9SLeon Romanovsky { 275c3d5c2d9SLeon Romanovsky struct device *dev = kobj_to_dev(kobj); 276c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev); 277c3d5c2d9SLeon Romanovsky 278c3d5c2d9SLeon Romanovsky if (!pdev->is_virtfn) 279c3d5c2d9SLeon Romanovsky return 0; 280c3d5c2d9SLeon Romanovsky 281c3d5c2d9SLeon Romanovsky return a->mode; 282c3d5c2d9SLeon Romanovsky } 283c3d5c2d9SLeon Romanovsky 284c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_vf_dev_attr_group = { 285c3d5c2d9SLeon Romanovsky .attrs = sriov_vf_dev_attrs, 286c3d5c2d9SLeon Romanovsky .is_visible = sriov_vf_attrs_are_visible, 287c3d5c2d9SLeon Romanovsky }; 288c3d5c2d9SLeon Romanovsky 289753f6124SJan H. Schönherr int pci_iov_add_virtfn(struct pci_dev *dev, int id) 290dd7cc44dSYu Zhao { 291dd7cc44dSYu Zhao int i; 292dc087f2fSJiang Liu int rc = -ENOMEM; 293dd7cc44dSYu Zhao u64 size; 294dd7cc44dSYu Zhao struct pci_dev *virtfn; 295dd7cc44dSYu Zhao struct resource *res; 296dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 2978b1fce04SGu Zheng struct pci_bus *bus; 298dd7cc44dSYu Zhao 299b07579c0SWei Yang bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id)); 300dc087f2fSJiang Liu if (!bus) 301dc087f2fSJiang Liu goto failed; 302dc087f2fSJiang Liu 303dc087f2fSJiang Liu virtfn = pci_alloc_dev(bus); 304dc087f2fSJiang Liu if (!virtfn) 305dc087f2fSJiang Liu goto failed0; 306dc087f2fSJiang Liu 307b07579c0SWei Yang virtfn->devfn = pci_iov_virtfn_devfn(dev, id); 308dd7cc44dSYu Zhao virtfn->vendor = dev->vendor; 3093142d832SFilippo Sironi virtfn->device = iov->vf_device; 310cf0921beSKarimAllah Ahmed virtfn->is_virtfn = 1; 311cf0921beSKarimAllah Ahmed virtfn->physfn = pci_dev_get(dev); 31212856e7aSMatthew Rosato virtfn->no_command_memory = 1; 313cf0921beSKarimAllah Ahmed 314cf0921beSKarimAllah Ahmed if (id == 0) 315cf0921beSKarimAllah Ahmed pci_read_vf_config_common(virtfn); 316cf0921beSKarimAllah Ahmed 317156c5532SPo Liu rc = pci_setup_device(virtfn); 318156c5532SPo Liu if (rc) 319cf0921beSKarimAllah Ahmed goto failed1; 320156c5532SPo Liu 321dd7cc44dSYu Zhao virtfn->dev.parent = dev->dev.parent; 322aa931977SAlex Williamson virtfn->multifunction = 0; 323dd7cc44dSYu Zhao 324dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 325c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 326dd7cc44dSYu Zhao if (!res->parent) 327dd7cc44dSYu Zhao continue; 328dd7cc44dSYu Zhao virtfn->resource[i].name = pci_name(virtfn); 329dd7cc44dSYu Zhao virtfn->resource[i].flags = res->flags; 3300e6c9122SWei Yang size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES); 331dd7cc44dSYu Zhao virtfn->resource[i].start = res->start + size * id; 332dd7cc44dSYu Zhao virtfn->resource[i].end = virtfn->resource[i].start + size - 1; 333dd7cc44dSYu Zhao rc = request_resource(res, &virtfn->resource[i]); 334dd7cc44dSYu Zhao BUG_ON(rc); 335dd7cc44dSYu Zhao } 336dd7cc44dSYu Zhao 337dd7cc44dSYu Zhao pci_device_add(virtfn, virtfn->bus); 338a1ceea67SNiklas Schnelle rc = pci_iov_sysfs_link(dev, virtfn, id); 339dd7cc44dSYu Zhao if (rc) 3408c386cc8SNavid Emamdoost goto failed1; 341dd7cc44dSYu Zhao 34227d61629SStuart Hayes pci_bus_add_device(virtfn); 34327d61629SStuart Hayes 344dd7cc44dSYu Zhao return 0; 345dd7cc44dSYu Zhao 346dd7cc44dSYu Zhao failed1: 3478c386cc8SNavid Emamdoost pci_stop_and_remove_bus_device(virtfn); 348dd7cc44dSYu Zhao pci_dev_put(dev); 349dc087f2fSJiang Liu failed0: 350dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, bus); 351dc087f2fSJiang Liu failed: 352dd7cc44dSYu Zhao 353dd7cc44dSYu Zhao return rc; 354dd7cc44dSYu Zhao } 355dd7cc44dSYu Zhao 356753f6124SJan H. Schönherr void pci_iov_remove_virtfn(struct pci_dev *dev, int id) 357dd7cc44dSYu Zhao { 358dd7cc44dSYu Zhao char buf[VIRTFN_ID_LEN]; 359dd7cc44dSYu Zhao struct pci_dev *virtfn; 360dd7cc44dSYu Zhao 361dc087f2fSJiang Liu virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), 362b07579c0SWei Yang pci_iov_virtfn_bus(dev, id), 363b07579c0SWei Yang pci_iov_virtfn_devfn(dev, id)); 364dd7cc44dSYu Zhao if (!virtfn) 365dd7cc44dSYu Zhao return; 366dd7cc44dSYu Zhao 367dd7cc44dSYu Zhao sprintf(buf, "virtfn%u", id); 368dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, buf); 36909cedbefSYinghai Lu /* 37009cedbefSYinghai Lu * pci_stop_dev() could have been called for this virtfn already, 37109cedbefSYinghai Lu * so the directory for the virtfn may have been removed before. 37209cedbefSYinghai Lu * Double check to avoid spurious sysfs warnings. 37309cedbefSYinghai Lu */ 37409cedbefSYinghai Lu if (virtfn->dev.kobj.sd) 375dd7cc44dSYu Zhao sysfs_remove_link(&virtfn->dev.kobj, "physfn"); 376dd7cc44dSYu Zhao 377210647afSYinghai Lu pci_stop_and_remove_bus_device(virtfn); 378dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, virtfn->bus); 379dd7cc44dSYu Zhao 380dc087f2fSJiang Liu /* balance pci_get_domain_bus_and_slot() */ 381dc087f2fSJiang Liu pci_dev_put(virtfn); 382dd7cc44dSYu Zhao pci_dev_put(dev); 383dd7cc44dSYu Zhao } 384dd7cc44dSYu Zhao 385aaee0c1fSKelsey Skunberg static ssize_t sriov_totalvfs_show(struct device *dev, 386aaee0c1fSKelsey Skunberg struct device_attribute *attr, 387aaee0c1fSKelsey Skunberg char *buf) 388aaee0c1fSKelsey Skunberg { 389aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 390aaee0c1fSKelsey Skunberg 391f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); 392aaee0c1fSKelsey Skunberg } 393aaee0c1fSKelsey Skunberg 394aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_show(struct device *dev, 395aaee0c1fSKelsey Skunberg struct device_attribute *attr, 396aaee0c1fSKelsey Skunberg char *buf) 397aaee0c1fSKelsey Skunberg { 398aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 39935ff867bSPierre Crégut u16 num_vfs; 400aaee0c1fSKelsey Skunberg 40135ff867bSPierre Crégut /* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */ 40235ff867bSPierre Crégut device_lock(&pdev->dev); 40335ff867bSPierre Crégut num_vfs = pdev->sriov->num_VFs; 40435ff867bSPierre Crégut device_unlock(&pdev->dev); 40535ff867bSPierre Crégut 406f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", num_vfs); 407aaee0c1fSKelsey Skunberg } 408aaee0c1fSKelsey Skunberg 409aaee0c1fSKelsey Skunberg /* 410aaee0c1fSKelsey Skunberg * num_vfs > 0; number of VFs to enable 411aaee0c1fSKelsey Skunberg * num_vfs = 0; disable all VFs 412aaee0c1fSKelsey Skunberg * 413aaee0c1fSKelsey Skunberg * Note: SRIOV spec does not allow partial VF 414aaee0c1fSKelsey Skunberg * disable, so it's all or none. 415aaee0c1fSKelsey Skunberg */ 416aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_store(struct device *dev, 417aaee0c1fSKelsey Skunberg struct device_attribute *attr, 418aaee0c1fSKelsey Skunberg const char *buf, size_t count) 419aaee0c1fSKelsey Skunberg { 420aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 42136f354ecSKrzysztof Wilczyński int ret = 0; 422aaee0c1fSKelsey Skunberg u16 num_vfs; 423aaee0c1fSKelsey Skunberg 42436f354ecSKrzysztof Wilczyński if (kstrtou16(buf, 0, &num_vfs) < 0) 42536f354ecSKrzysztof Wilczyński return -EINVAL; 426aaee0c1fSKelsey Skunberg 427aaee0c1fSKelsey Skunberg if (num_vfs > pci_sriov_get_totalvfs(pdev)) 428aaee0c1fSKelsey Skunberg return -ERANGE; 429aaee0c1fSKelsey Skunberg 430aaee0c1fSKelsey Skunberg device_lock(&pdev->dev); 431aaee0c1fSKelsey Skunberg 432aaee0c1fSKelsey Skunberg if (num_vfs == pdev->sriov->num_VFs) 433aaee0c1fSKelsey Skunberg goto exit; 434aaee0c1fSKelsey Skunberg 435e9c3bbd6SMoritz Fischer /* is PF driver loaded */ 436e0217c5bSBjorn Helgaas if (!pdev->driver) { 437e9c3bbd6SMoritz Fischer pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n"); 438e9c3bbd6SMoritz Fischer ret = -ENOENT; 439e9c3bbd6SMoritz Fischer goto exit; 440e9c3bbd6SMoritz Fischer } 441e9c3bbd6SMoritz Fischer 442aaee0c1fSKelsey Skunberg /* is PF driver loaded w/callback */ 443e0217c5bSBjorn Helgaas if (!pdev->driver->sriov_configure) { 444e9c3bbd6SMoritz Fischer pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n"); 445aaee0c1fSKelsey Skunberg ret = -ENOENT; 446aaee0c1fSKelsey Skunberg goto exit; 447aaee0c1fSKelsey Skunberg } 448aaee0c1fSKelsey Skunberg 449aaee0c1fSKelsey Skunberg if (num_vfs == 0) { 450aaee0c1fSKelsey Skunberg /* disable VFs */ 451e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_configure(pdev, 0); 452aaee0c1fSKelsey Skunberg goto exit; 453aaee0c1fSKelsey Skunberg } 454aaee0c1fSKelsey Skunberg 455aaee0c1fSKelsey Skunberg /* enable VFs */ 456aaee0c1fSKelsey Skunberg if (pdev->sriov->num_VFs) { 457aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n", 458aaee0c1fSKelsey Skunberg pdev->sriov->num_VFs, num_vfs); 459aaee0c1fSKelsey Skunberg ret = -EBUSY; 460aaee0c1fSKelsey Skunberg goto exit; 461aaee0c1fSKelsey Skunberg } 462aaee0c1fSKelsey Skunberg 463e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_configure(pdev, num_vfs); 464aaee0c1fSKelsey Skunberg if (ret < 0) 465aaee0c1fSKelsey Skunberg goto exit; 466aaee0c1fSKelsey Skunberg 467aaee0c1fSKelsey Skunberg if (ret != num_vfs) 468aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs requested; only %d enabled\n", 469aaee0c1fSKelsey Skunberg num_vfs, ret); 470aaee0c1fSKelsey Skunberg 471aaee0c1fSKelsey Skunberg exit: 472aaee0c1fSKelsey Skunberg device_unlock(&pdev->dev); 473aaee0c1fSKelsey Skunberg 474aaee0c1fSKelsey Skunberg if (ret < 0) 475aaee0c1fSKelsey Skunberg return ret; 476aaee0c1fSKelsey Skunberg 477aaee0c1fSKelsey Skunberg return count; 478aaee0c1fSKelsey Skunberg } 479aaee0c1fSKelsey Skunberg 480aaee0c1fSKelsey Skunberg static ssize_t sriov_offset_show(struct device *dev, 481aaee0c1fSKelsey Skunberg struct device_attribute *attr, 482aaee0c1fSKelsey Skunberg char *buf) 483aaee0c1fSKelsey Skunberg { 484aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 485aaee0c1fSKelsey Skunberg 486f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->offset); 487aaee0c1fSKelsey Skunberg } 488aaee0c1fSKelsey Skunberg 489aaee0c1fSKelsey Skunberg static ssize_t sriov_stride_show(struct device *dev, 490aaee0c1fSKelsey Skunberg struct device_attribute *attr, 491aaee0c1fSKelsey Skunberg char *buf) 492aaee0c1fSKelsey Skunberg { 493aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 494aaee0c1fSKelsey Skunberg 495f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->stride); 496aaee0c1fSKelsey Skunberg } 497aaee0c1fSKelsey Skunberg 498aaee0c1fSKelsey Skunberg static ssize_t sriov_vf_device_show(struct device *dev, 499aaee0c1fSKelsey Skunberg struct device_attribute *attr, 500aaee0c1fSKelsey Skunberg char *buf) 501aaee0c1fSKelsey Skunberg { 502aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 503aaee0c1fSKelsey Skunberg 504f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device); 505aaee0c1fSKelsey Skunberg } 506aaee0c1fSKelsey Skunberg 507aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_show(struct device *dev, 508aaee0c1fSKelsey Skunberg struct device_attribute *attr, 509aaee0c1fSKelsey Skunberg char *buf) 510aaee0c1fSKelsey Skunberg { 511aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 512aaee0c1fSKelsey Skunberg 513f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe); 514aaee0c1fSKelsey Skunberg } 515aaee0c1fSKelsey Skunberg 516aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_store(struct device *dev, 517aaee0c1fSKelsey Skunberg struct device_attribute *attr, 518aaee0c1fSKelsey Skunberg const char *buf, size_t count) 519aaee0c1fSKelsey Skunberg { 520aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 521aaee0c1fSKelsey Skunberg bool drivers_autoprobe; 522aaee0c1fSKelsey Skunberg 523aaee0c1fSKelsey Skunberg if (kstrtobool(buf, &drivers_autoprobe) < 0) 524aaee0c1fSKelsey Skunberg return -EINVAL; 525aaee0c1fSKelsey Skunberg 526aaee0c1fSKelsey Skunberg pdev->sriov->drivers_autoprobe = drivers_autoprobe; 527aaee0c1fSKelsey Skunberg 528aaee0c1fSKelsey Skunberg return count; 529aaee0c1fSKelsey Skunberg } 530aaee0c1fSKelsey Skunberg 531aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_totalvfs); 532244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_numvfs); 533aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_offset); 534aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_stride); 535aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_vf_device); 536244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_drivers_autoprobe); 537aaee0c1fSKelsey Skunberg 538c3d5c2d9SLeon Romanovsky static struct attribute *sriov_pf_dev_attrs[] = { 539aaee0c1fSKelsey Skunberg &dev_attr_sriov_totalvfs.attr, 540aaee0c1fSKelsey Skunberg &dev_attr_sriov_numvfs.attr, 541aaee0c1fSKelsey Skunberg &dev_attr_sriov_offset.attr, 542aaee0c1fSKelsey Skunberg &dev_attr_sriov_stride.attr, 543aaee0c1fSKelsey Skunberg &dev_attr_sriov_vf_device.attr, 544aaee0c1fSKelsey Skunberg &dev_attr_sriov_drivers_autoprobe.attr, 545c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 546c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_total_msix.attr, 547c3d5c2d9SLeon Romanovsky #endif 548aaee0c1fSKelsey Skunberg NULL, 549aaee0c1fSKelsey Skunberg }; 550aaee0c1fSKelsey Skunberg 551c3d5c2d9SLeon Romanovsky static umode_t sriov_pf_attrs_are_visible(struct kobject *kobj, 552aaee0c1fSKelsey Skunberg struct attribute *a, int n) 553aaee0c1fSKelsey Skunberg { 554aaee0c1fSKelsey Skunberg struct device *dev = kobj_to_dev(kobj); 555aaee0c1fSKelsey Skunberg 556aaee0c1fSKelsey Skunberg if (!dev_is_pf(dev)) 557aaee0c1fSKelsey Skunberg return 0; 558aaee0c1fSKelsey Skunberg 559aaee0c1fSKelsey Skunberg return a->mode; 560aaee0c1fSKelsey Skunberg } 561aaee0c1fSKelsey Skunberg 562c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_pf_dev_attr_group = { 563c3d5c2d9SLeon Romanovsky .attrs = sriov_pf_dev_attrs, 564c3d5c2d9SLeon Romanovsky .is_visible = sriov_pf_attrs_are_visible, 565aaee0c1fSKelsey Skunberg }; 566aaee0c1fSKelsey Skunberg 567995df527SWei Yang int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs) 568995df527SWei Yang { 569995df527SWei Yang return 0; 570995df527SWei Yang } 571995df527SWei Yang 572a39e3fcdSAlexander Duyck int __weak pcibios_sriov_disable(struct pci_dev *pdev) 573a39e3fcdSAlexander Duyck { 574a39e3fcdSAlexander Duyck return 0; 575a39e3fcdSAlexander Duyck } 576a39e3fcdSAlexander Duyck 57718f9e9d1SSebastian Ott static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) 57818f9e9d1SSebastian Ott { 57918f9e9d1SSebastian Ott unsigned int i; 58018f9e9d1SSebastian Ott int rc; 58118f9e9d1SSebastian Ott 582aff68a5aSSebastian Ott if (dev->no_vf_scan) 583aff68a5aSSebastian Ott return 0; 584aff68a5aSSebastian Ott 58518f9e9d1SSebastian Ott for (i = 0; i < num_vfs; i++) { 58618f9e9d1SSebastian Ott rc = pci_iov_add_virtfn(dev, i); 58718f9e9d1SSebastian Ott if (rc) 58818f9e9d1SSebastian Ott goto failed; 58918f9e9d1SSebastian Ott } 59018f9e9d1SSebastian Ott return 0; 59118f9e9d1SSebastian Ott failed: 59218f9e9d1SSebastian Ott while (i--) 59318f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 59418f9e9d1SSebastian Ott 59518f9e9d1SSebastian Ott return rc; 59618f9e9d1SSebastian Ott } 59718f9e9d1SSebastian Ott 598dd7cc44dSYu Zhao static int sriov_enable(struct pci_dev *dev, int nr_virtfn) 599dd7cc44dSYu Zhao { 600dd7cc44dSYu Zhao int rc; 6013443c382SAlexander Duyck int i; 602dd7cc44dSYu Zhao int nres; 603ce288ec3SAlexander Duyck u16 initial; 604dd7cc44dSYu Zhao struct resource *res; 605dd7cc44dSYu Zhao struct pci_dev *pdev; 606dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 607bbef98abSRam Pai int bars = 0; 608b07579c0SWei Yang int bus; 609dd7cc44dSYu Zhao 610dd7cc44dSYu Zhao if (!nr_virtfn) 611dd7cc44dSYu Zhao return 0; 612dd7cc44dSYu Zhao 6136b136724SBjorn Helgaas if (iov->num_VFs) 614dd7cc44dSYu Zhao return -EINVAL; 615dd7cc44dSYu Zhao 616dd7cc44dSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); 6176b136724SBjorn Helgaas if (initial > iov->total_VFs || 6186b136724SBjorn Helgaas (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs))) 619dd7cc44dSYu Zhao return -EIO; 620dd7cc44dSYu Zhao 6216b136724SBjorn Helgaas if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs || 622dd7cc44dSYu Zhao (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) 623dd7cc44dSYu Zhao return -EINVAL; 624dd7cc44dSYu Zhao 625dd7cc44dSYu Zhao nres = 0; 626dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 627bbef98abSRam Pai bars |= (1 << (i + PCI_IOV_RESOURCES)); 628c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 629dd7cc44dSYu Zhao if (res->parent) 630dd7cc44dSYu Zhao nres++; 631dd7cc44dSYu Zhao } 632dd7cc44dSYu Zhao if (nres != iov->nres) { 6337506dc79SFrederick Lawler pci_err(dev, "not enough MMIO resources for SR-IOV\n"); 634dd7cc44dSYu Zhao return -ENOMEM; 635dd7cc44dSYu Zhao } 636dd7cc44dSYu Zhao 637b07579c0SWei Yang bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 63868f8e9faSBjorn Helgaas if (bus > dev->bus->busn_res.end) { 6397506dc79SFrederick Lawler pci_err(dev, "can't enable %d VFs (bus %02x out of range of %pR)\n", 64068f8e9faSBjorn Helgaas nr_virtfn, bus, &dev->bus->busn_res); 641dd7cc44dSYu Zhao return -ENOMEM; 642dd7cc44dSYu Zhao } 643dd7cc44dSYu Zhao 644bbef98abSRam Pai if (pci_enable_resources(dev, bars)) { 6457506dc79SFrederick Lawler pci_err(dev, "SR-IOV: IOV BARS not allocated\n"); 646bbef98abSRam Pai return -ENOMEM; 647bbef98abSRam Pai } 648bbef98abSRam Pai 649dd7cc44dSYu Zhao if (iov->link != dev->devfn) { 650dd7cc44dSYu Zhao pdev = pci_get_slot(dev->bus, iov->link); 651dd7cc44dSYu Zhao if (!pdev) 652dd7cc44dSYu Zhao return -ENODEV; 653dd7cc44dSYu Zhao 654dc087f2fSJiang Liu if (!pdev->is_physfn) { 655dd7cc44dSYu Zhao pci_dev_put(pdev); 656652d1100SStefan Assmann return -ENOSYS; 657dc087f2fSJiang Liu } 658dd7cc44dSYu Zhao 659dd7cc44dSYu Zhao rc = sysfs_create_link(&dev->dev.kobj, 660dd7cc44dSYu Zhao &pdev->dev.kobj, "dep_link"); 661dc087f2fSJiang Liu pci_dev_put(pdev); 662dd7cc44dSYu Zhao if (rc) 663dd7cc44dSYu Zhao return rc; 664dd7cc44dSYu Zhao } 665dd7cc44dSYu Zhao 6666b136724SBjorn Helgaas iov->initial_VFs = initial; 667dd7cc44dSYu Zhao if (nr_virtfn < initial) 668dd7cc44dSYu Zhao initial = nr_virtfn; 669dd7cc44dSYu Zhao 670c23b6135SAlexander Duyck rc = pcibios_sriov_enable(dev, initial); 671c23b6135SAlexander Duyck if (rc) { 6727506dc79SFrederick Lawler pci_err(dev, "failure %d from pcibios_sriov_enable()\n", rc); 673c23b6135SAlexander Duyck goto err_pcibios; 674995df527SWei Yang } 675995df527SWei Yang 676f40ec3c7SGavin Shan pci_iov_set_numvfs(dev, nr_virtfn); 677f40ec3c7SGavin Shan iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; 678f40ec3c7SGavin Shan pci_cfg_access_lock(dev); 679f40ec3c7SGavin Shan pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 680f40ec3c7SGavin Shan msleep(100); 681f40ec3c7SGavin Shan pci_cfg_access_unlock(dev); 682f40ec3c7SGavin Shan 68318f9e9d1SSebastian Ott rc = sriov_add_vfs(dev, initial); 684dd7cc44dSYu Zhao if (rc) 68518f9e9d1SSebastian Ott goto err_pcibios; 686dd7cc44dSYu Zhao 687dd7cc44dSYu Zhao kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); 6886b136724SBjorn Helgaas iov->num_VFs = nr_virtfn; 689dd7cc44dSYu Zhao 690dd7cc44dSYu Zhao return 0; 691dd7cc44dSYu Zhao 692c23b6135SAlexander Duyck err_pcibios: 693dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 694fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 695dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 696dd7cc44dSYu Zhao ssleep(1); 697fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 698dd7cc44dSYu Zhao 6990fc690a7SGavin Shan pcibios_sriov_disable(dev); 7000fc690a7SGavin Shan 701dd7cc44dSYu Zhao if (iov->link != dev->devfn) 702dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 703dd7cc44dSYu Zhao 704b3908644SAlexander Duyck pci_iov_set_numvfs(dev, 0); 705dd7cc44dSYu Zhao return rc; 706dd7cc44dSYu Zhao } 707dd7cc44dSYu Zhao 70818f9e9d1SSebastian Ott static void sriov_del_vfs(struct pci_dev *dev) 70918f9e9d1SSebastian Ott { 71018f9e9d1SSebastian Ott struct pci_sriov *iov = dev->sriov; 71118f9e9d1SSebastian Ott int i; 71218f9e9d1SSebastian Ott 71318f9e9d1SSebastian Ott for (i = 0; i < iov->num_VFs; i++) 71418f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 71518f9e9d1SSebastian Ott } 71618f9e9d1SSebastian Ott 717dd7cc44dSYu Zhao static void sriov_disable(struct pci_dev *dev) 718dd7cc44dSYu Zhao { 719dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 720dd7cc44dSYu Zhao 7216b136724SBjorn Helgaas if (!iov->num_VFs) 722dd7cc44dSYu Zhao return; 723dd7cc44dSYu Zhao 72418f9e9d1SSebastian Ott sriov_del_vfs(dev); 725dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 726fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 727dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 728dd7cc44dSYu Zhao ssleep(1); 729fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 730dd7cc44dSYu Zhao 7310fc690a7SGavin Shan pcibios_sriov_disable(dev); 7320fc690a7SGavin Shan 733dd7cc44dSYu Zhao if (iov->link != dev->devfn) 734dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 735dd7cc44dSYu Zhao 7366b136724SBjorn Helgaas iov->num_VFs = 0; 737f59dca27SWei Yang pci_iov_set_numvfs(dev, 0); 738dd7cc44dSYu Zhao } 739dd7cc44dSYu Zhao 740d1b054daSYu Zhao static int sriov_init(struct pci_dev *dev, int pos) 741d1b054daSYu Zhao { 7420e6c9122SWei Yang int i, bar64; 743d1b054daSYu Zhao int rc; 744d1b054daSYu Zhao int nres; 745d1b054daSYu Zhao u32 pgsz; 746ea9a8854SAlexander Duyck u16 ctrl, total; 747d1b054daSYu Zhao struct pci_sriov *iov; 748d1b054daSYu Zhao struct resource *res; 749d1b054daSYu Zhao struct pci_dev *pdev; 750d1b054daSYu Zhao 751d1b054daSYu Zhao pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl); 752d1b054daSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) { 753d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0); 754d1b054daSYu Zhao ssleep(1); 755d1b054daSYu Zhao } 756d1b054daSYu Zhao 757d1b054daSYu Zhao ctrl = 0; 758d1b054daSYu Zhao list_for_each_entry(pdev, &dev->bus->devices, bus_list) 759d1b054daSYu Zhao if (pdev->is_physfn) 760d1b054daSYu Zhao goto found; 761d1b054daSYu Zhao 762d1b054daSYu Zhao pdev = NULL; 763d1b054daSYu Zhao if (pci_ari_enabled(dev->bus)) 764d1b054daSYu Zhao ctrl |= PCI_SRIOV_CTRL_ARI; 765d1b054daSYu Zhao 766d1b054daSYu Zhao found: 767d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); 768d1b054daSYu Zhao 769ff45f9ddSBen Shelton pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); 770ff45f9ddSBen Shelton if (!total) 771ff45f9ddSBen Shelton return 0; 772d1b054daSYu Zhao 773d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz); 774d1b054daSYu Zhao i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0; 775d1b054daSYu Zhao pgsz &= ~((1 << i) - 1); 776d1b054daSYu Zhao if (!pgsz) 777d1b054daSYu Zhao return -EIO; 778d1b054daSYu Zhao 779d1b054daSYu Zhao pgsz &= ~(pgsz - 1); 7808161fe91SVaidyanathan Srinivasan pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); 781d1b054daSYu Zhao 7820e6c9122SWei Yang iov = kzalloc(sizeof(*iov), GFP_KERNEL); 7830e6c9122SWei Yang if (!iov) 7840e6c9122SWei Yang return -ENOMEM; 7850e6c9122SWei Yang 786d1b054daSYu Zhao nres = 0; 787d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 788c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 78911183991SDavid Daney /* 79011183991SDavid Daney * If it is already FIXED, don't change it, something 79111183991SDavid Daney * (perhaps EA or header fixups) wants it this way. 79211183991SDavid Daney */ 79311183991SDavid Daney if (res->flags & IORESOURCE_PCI_FIXED) 79411183991SDavid Daney bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0; 79511183991SDavid Daney else 7960e6c9122SWei Yang bar64 = __pci_read_base(dev, pci_bar_unknown, res, 797d1b054daSYu Zhao pos + PCI_SRIOV_BAR + i * 4); 798d1b054daSYu Zhao if (!res->flags) 799d1b054daSYu Zhao continue; 800d1b054daSYu Zhao if (resource_size(res) & (PAGE_SIZE - 1)) { 801d1b054daSYu Zhao rc = -EIO; 802d1b054daSYu Zhao goto failed; 803d1b054daSYu Zhao } 8040e6c9122SWei Yang iov->barsz[i] = resource_size(res); 805d1b054daSYu Zhao res->end = res->start + resource_size(res) * total - 1; 8067506dc79SFrederick Lawler pci_info(dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n", 807e88ae01dSWei Yang i, res, i, total); 8080e6c9122SWei Yang i += bar64; 809d1b054daSYu Zhao nres++; 810d1b054daSYu Zhao } 811d1b054daSYu Zhao 812d1b054daSYu Zhao iov->pos = pos; 813d1b054daSYu Zhao iov->nres = nres; 814d1b054daSYu Zhao iov->ctrl = ctrl; 8156b136724SBjorn Helgaas iov->total_VFs = total; 8168d85a7a4SJakub Kicinski iov->driver_max_VFs = total; 8173142d832SFilippo Sironi pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device); 818d1b054daSYu Zhao iov->pgsz = pgsz; 819d1b054daSYu Zhao iov->self = dev; 8200e7df224SBodong Wang iov->drivers_autoprobe = true; 821d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); 822d1b054daSYu Zhao pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 82362f87c0eSYijing Wang if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) 8244d135dbeSYu Zhao iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link); 825d1b054daSYu Zhao 826d1b054daSYu Zhao if (pdev) 827d1b054daSYu Zhao iov->dev = pci_dev_get(pdev); 828e277d2fcSYu Zhao else 829d1b054daSYu Zhao iov->dev = dev; 830e277d2fcSYu Zhao 831d1b054daSYu Zhao dev->sriov = iov; 832d1b054daSYu Zhao dev->is_physfn = 1; 833ea9a8854SAlexander Duyck rc = compute_max_vf_buses(dev); 834ea9a8854SAlexander Duyck if (rc) 835ea9a8854SAlexander Duyck goto fail_max_buses; 836d1b054daSYu Zhao 837d1b054daSYu Zhao return 0; 838d1b054daSYu Zhao 839ea9a8854SAlexander Duyck fail_max_buses: 840ea9a8854SAlexander Duyck dev->sriov = NULL; 841ea9a8854SAlexander Duyck dev->is_physfn = 0; 842d1b054daSYu Zhao failed: 843d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 844c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 845d1b054daSYu Zhao res->flags = 0; 846d1b054daSYu Zhao } 847d1b054daSYu Zhao 8480e6c9122SWei Yang kfree(iov); 849d1b054daSYu Zhao return rc; 850d1b054daSYu Zhao } 851d1b054daSYu Zhao 852d1b054daSYu Zhao static void sriov_release(struct pci_dev *dev) 853d1b054daSYu Zhao { 8546b136724SBjorn Helgaas BUG_ON(dev->sriov->num_VFs); 855dd7cc44dSYu Zhao 856e277d2fcSYu Zhao if (dev != dev->sriov->dev) 857d1b054daSYu Zhao pci_dev_put(dev->sriov->dev); 858d1b054daSYu Zhao 859d1b054daSYu Zhao kfree(dev->sriov); 860d1b054daSYu Zhao dev->sriov = NULL; 861d1b054daSYu Zhao } 862d1b054daSYu Zhao 8638c5cdb6aSYu Zhao static void sriov_restore_state(struct pci_dev *dev) 8648c5cdb6aSYu Zhao { 8658c5cdb6aSYu Zhao int i; 8668c5cdb6aSYu Zhao u16 ctrl; 8678c5cdb6aSYu Zhao struct pci_sriov *iov = dev->sriov; 8688c5cdb6aSYu Zhao 8698c5cdb6aSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl); 8708c5cdb6aSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) 8718c5cdb6aSYu Zhao return; 8728c5cdb6aSYu Zhao 873ff26449eSTony Nguyen /* 874ff26449eSTony Nguyen * Restore PCI_SRIOV_CTRL_ARI before pci_iov_set_numvfs() because 875ff26449eSTony Nguyen * it reads offset & stride, which depend on PCI_SRIOV_CTRL_ARI. 876ff26449eSTony Nguyen */ 877ff26449eSTony Nguyen ctrl &= ~PCI_SRIOV_CTRL_ARI; 878ff26449eSTony Nguyen ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI; 879ff26449eSTony Nguyen pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl); 880ff26449eSTony Nguyen 88139098edbSDenis Efremov for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) 88239098edbSDenis Efremov pci_update_resource(dev, i + PCI_IOV_RESOURCES); 8838c5cdb6aSYu Zhao 8848c5cdb6aSYu Zhao pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); 885f59dca27SWei Yang pci_iov_set_numvfs(dev, iov->num_VFs); 8868c5cdb6aSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 8878c5cdb6aSYu Zhao if (iov->ctrl & PCI_SRIOV_CTRL_VFE) 8888c5cdb6aSYu Zhao msleep(100); 8898c5cdb6aSYu Zhao } 8908c5cdb6aSYu Zhao 891d1b054daSYu Zhao /** 892d1b054daSYu Zhao * pci_iov_init - initialize the IOV capability 893d1b054daSYu Zhao * @dev: the PCI device 894d1b054daSYu Zhao * 895d1b054daSYu Zhao * Returns 0 on success, or negative on failure. 896d1b054daSYu Zhao */ 897d1b054daSYu Zhao int pci_iov_init(struct pci_dev *dev) 898d1b054daSYu Zhao { 899d1b054daSYu Zhao int pos; 900d1b054daSYu Zhao 9015f4d91a1SKenji Kaneshige if (!pci_is_pcie(dev)) 902d1b054daSYu Zhao return -ENODEV; 903d1b054daSYu Zhao 904d1b054daSYu Zhao pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); 905d1b054daSYu Zhao if (pos) 906d1b054daSYu Zhao return sriov_init(dev, pos); 907d1b054daSYu Zhao 908d1b054daSYu Zhao return -ENODEV; 909d1b054daSYu Zhao } 910d1b054daSYu Zhao 911d1b054daSYu Zhao /** 912d1b054daSYu Zhao * pci_iov_release - release resources used by the IOV capability 913d1b054daSYu Zhao * @dev: the PCI device 914d1b054daSYu Zhao */ 915d1b054daSYu Zhao void pci_iov_release(struct pci_dev *dev) 916d1b054daSYu Zhao { 917d1b054daSYu Zhao if (dev->is_physfn) 918d1b054daSYu Zhao sriov_release(dev); 919d1b054daSYu Zhao } 920d1b054daSYu Zhao 921d1b054daSYu Zhao /** 92238972375SJakub Kicinski * pci_iov_remove - clean up SR-IOV state after PF driver is detached 92338972375SJakub Kicinski * @dev: the PCI device 92438972375SJakub Kicinski */ 92538972375SJakub Kicinski void pci_iov_remove(struct pci_dev *dev) 92638972375SJakub Kicinski { 92738972375SJakub Kicinski struct pci_sriov *iov = dev->sriov; 92838972375SJakub Kicinski 92938972375SJakub Kicinski if (!dev->is_physfn) 93038972375SJakub Kicinski return; 93138972375SJakub Kicinski 93238972375SJakub Kicinski iov->driver_max_VFs = iov->total_VFs; 93338972375SJakub Kicinski if (iov->num_VFs) 93438972375SJakub Kicinski pci_warn(dev, "driver left SR-IOV enabled after remove\n"); 93538972375SJakub Kicinski } 93638972375SJakub Kicinski 93738972375SJakub Kicinski /** 9386ffa2489SBjorn Helgaas * pci_iov_update_resource - update a VF BAR 9396ffa2489SBjorn Helgaas * @dev: the PCI device 9406ffa2489SBjorn Helgaas * @resno: the resource number 9416ffa2489SBjorn Helgaas * 9426ffa2489SBjorn Helgaas * Update a VF BAR in the SR-IOV capability of a PF. 9436ffa2489SBjorn Helgaas */ 9446ffa2489SBjorn Helgaas void pci_iov_update_resource(struct pci_dev *dev, int resno) 9456ffa2489SBjorn Helgaas { 9466ffa2489SBjorn Helgaas struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; 9476ffa2489SBjorn Helgaas struct resource *res = dev->resource + resno; 9486ffa2489SBjorn Helgaas int vf_bar = resno - PCI_IOV_RESOURCES; 9496ffa2489SBjorn Helgaas struct pci_bus_region region; 950546ba9f8SBjorn Helgaas u16 cmd; 9516ffa2489SBjorn Helgaas u32 new; 9526ffa2489SBjorn Helgaas int reg; 9536ffa2489SBjorn Helgaas 9546ffa2489SBjorn Helgaas /* 9556ffa2489SBjorn Helgaas * The generic pci_restore_bars() path calls this for all devices, 9566ffa2489SBjorn Helgaas * including VFs and non-SR-IOV devices. If this is not a PF, we 9576ffa2489SBjorn Helgaas * have nothing to do. 9586ffa2489SBjorn Helgaas */ 9596ffa2489SBjorn Helgaas if (!iov) 9606ffa2489SBjorn Helgaas return; 9616ffa2489SBjorn Helgaas 962546ba9f8SBjorn Helgaas pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); 963546ba9f8SBjorn Helgaas if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { 964546ba9f8SBjorn Helgaas dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", 965546ba9f8SBjorn Helgaas vf_bar, res); 966546ba9f8SBjorn Helgaas return; 967546ba9f8SBjorn Helgaas } 968546ba9f8SBjorn Helgaas 9696ffa2489SBjorn Helgaas /* 9706ffa2489SBjorn Helgaas * Ignore unimplemented BARs, unused resource slots for 64-bit 9716ffa2489SBjorn Helgaas * BARs, and non-movable resources, e.g., those described via 9726ffa2489SBjorn Helgaas * Enhanced Allocation. 9736ffa2489SBjorn Helgaas */ 9746ffa2489SBjorn Helgaas if (!res->flags) 9756ffa2489SBjorn Helgaas return; 9766ffa2489SBjorn Helgaas 9776ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_UNSET) 9786ffa2489SBjorn Helgaas return; 9796ffa2489SBjorn Helgaas 9806ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_PCI_FIXED) 9816ffa2489SBjorn Helgaas return; 9826ffa2489SBjorn Helgaas 9836ffa2489SBjorn Helgaas pcibios_resource_to_bus(dev->bus, ®ion, res); 9846ffa2489SBjorn Helgaas new = region.start; 9856ffa2489SBjorn Helgaas new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; 9866ffa2489SBjorn Helgaas 9876ffa2489SBjorn Helgaas reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar; 9886ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg, new); 9896ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_MEM_64) { 9906ffa2489SBjorn Helgaas new = region.start >> 16 >> 16; 9916ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg + 4, new); 9926ffa2489SBjorn Helgaas } 9936ffa2489SBjorn Helgaas } 9946ffa2489SBjorn Helgaas 995978d2d68SWei Yang resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev, 996978d2d68SWei Yang int resno) 997978d2d68SWei Yang { 998978d2d68SWei Yang return pci_iov_resource_size(dev, resno); 999978d2d68SWei Yang } 1000978d2d68SWei Yang 10018c5cdb6aSYu Zhao /** 10026faf17f6SChris Wright * pci_sriov_resource_alignment - get resource alignment for VF BAR 10036faf17f6SChris Wright * @dev: the PCI device 10046faf17f6SChris Wright * @resno: the resource number 10056faf17f6SChris Wright * 10066faf17f6SChris Wright * Returns the alignment of the VF BAR found in the SR-IOV capability. 10076faf17f6SChris Wright * This is not the same as the resource size which is defined as 10086faf17f6SChris Wright * the VF BAR size multiplied by the number of VFs. The alignment 10096faf17f6SChris Wright * is just the VF BAR size. 10106faf17f6SChris Wright */ 10110e52247aSCam Macdonell resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) 10126faf17f6SChris Wright { 1013978d2d68SWei Yang return pcibios_iov_resource_alignment(dev, resno); 10146faf17f6SChris Wright } 10156faf17f6SChris Wright 10166faf17f6SChris Wright /** 10178c5cdb6aSYu Zhao * pci_restore_iov_state - restore the state of the IOV capability 10188c5cdb6aSYu Zhao * @dev: the PCI device 10198c5cdb6aSYu Zhao */ 10208c5cdb6aSYu Zhao void pci_restore_iov_state(struct pci_dev *dev) 10218c5cdb6aSYu Zhao { 10228c5cdb6aSYu Zhao if (dev->is_physfn) 10238c5cdb6aSYu Zhao sriov_restore_state(dev); 10248c5cdb6aSYu Zhao } 1025a28724b0SYu Zhao 1026a28724b0SYu Zhao /** 1027608c0d88SBryant G. Ly * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs 1028608c0d88SBryant G. Ly * @dev: the PCI device 1029608c0d88SBryant G. Ly * @auto_probe: set VF drivers auto probe flag 1030608c0d88SBryant G. Ly */ 1031608c0d88SBryant G. Ly void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe) 1032608c0d88SBryant G. Ly { 1033608c0d88SBryant G. Ly if (dev->is_physfn) 1034608c0d88SBryant G. Ly dev->sriov->drivers_autoprobe = auto_probe; 1035608c0d88SBryant G. Ly } 1036608c0d88SBryant G. Ly 1037608c0d88SBryant G. Ly /** 1038a28724b0SYu Zhao * pci_iov_bus_range - find bus range used by Virtual Function 1039a28724b0SYu Zhao * @bus: the PCI bus 1040a28724b0SYu Zhao * 1041a28724b0SYu Zhao * Returns max number of buses (exclude current one) used by Virtual 1042a28724b0SYu Zhao * Functions. 1043a28724b0SYu Zhao */ 1044a28724b0SYu Zhao int pci_iov_bus_range(struct pci_bus *bus) 1045a28724b0SYu Zhao { 1046a28724b0SYu Zhao int max = 0; 1047a28724b0SYu Zhao struct pci_dev *dev; 1048a28724b0SYu Zhao 1049a28724b0SYu Zhao list_for_each_entry(dev, &bus->devices, bus_list) { 1050a28724b0SYu Zhao if (!dev->is_physfn) 1051a28724b0SYu Zhao continue; 10524449f079SWei Yang if (dev->sriov->max_VF_buses > max) 10534449f079SWei Yang max = dev->sriov->max_VF_buses; 1054a28724b0SYu Zhao } 1055a28724b0SYu Zhao 1056a28724b0SYu Zhao return max ? max - bus->number : 0; 1057a28724b0SYu Zhao } 1058dd7cc44dSYu Zhao 1059dd7cc44dSYu Zhao /** 1060dd7cc44dSYu Zhao * pci_enable_sriov - enable the SR-IOV capability 1061dd7cc44dSYu Zhao * @dev: the PCI device 106252a8873bSRandy Dunlap * @nr_virtfn: number of virtual functions to enable 1063dd7cc44dSYu Zhao * 1064dd7cc44dSYu Zhao * Returns 0 on success, or negative on failure. 1065dd7cc44dSYu Zhao */ 1066dd7cc44dSYu Zhao int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) 1067dd7cc44dSYu Zhao { 1068dd7cc44dSYu Zhao might_sleep(); 1069dd7cc44dSYu Zhao 1070dd7cc44dSYu Zhao if (!dev->is_physfn) 1071652d1100SStefan Assmann return -ENOSYS; 1072dd7cc44dSYu Zhao 1073dd7cc44dSYu Zhao return sriov_enable(dev, nr_virtfn); 1074dd7cc44dSYu Zhao } 1075dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_enable_sriov); 1076dd7cc44dSYu Zhao 1077dd7cc44dSYu Zhao /** 1078dd7cc44dSYu Zhao * pci_disable_sriov - disable the SR-IOV capability 1079dd7cc44dSYu Zhao * @dev: the PCI device 1080dd7cc44dSYu Zhao */ 1081dd7cc44dSYu Zhao void pci_disable_sriov(struct pci_dev *dev) 1082dd7cc44dSYu Zhao { 1083dd7cc44dSYu Zhao might_sleep(); 1084dd7cc44dSYu Zhao 1085dd7cc44dSYu Zhao if (!dev->is_physfn) 1086dd7cc44dSYu Zhao return; 1087dd7cc44dSYu Zhao 1088dd7cc44dSYu Zhao sriov_disable(dev); 1089dd7cc44dSYu Zhao } 1090dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_disable_sriov); 109174bb1bccSYu Zhao 109274bb1bccSYu Zhao /** 1093fb8a0d9dSWilliams, Mitch A * pci_num_vf - return number of VFs associated with a PF device_release_driver 1094fb8a0d9dSWilliams, Mitch A * @dev: the PCI device 1095fb8a0d9dSWilliams, Mitch A * 1096fb8a0d9dSWilliams, Mitch A * Returns number of VFs, or 0 if SR-IOV is not enabled. 1097fb8a0d9dSWilliams, Mitch A */ 1098fb8a0d9dSWilliams, Mitch A int pci_num_vf(struct pci_dev *dev) 1099fb8a0d9dSWilliams, Mitch A { 11001452cd76SBjorn Helgaas if (!dev->is_physfn) 1101fb8a0d9dSWilliams, Mitch A return 0; 11021452cd76SBjorn Helgaas 11036b136724SBjorn Helgaas return dev->sriov->num_VFs; 1104fb8a0d9dSWilliams, Mitch A } 1105fb8a0d9dSWilliams, Mitch A EXPORT_SYMBOL_GPL(pci_num_vf); 1106bff73156SDonald Dutile 1107bff73156SDonald Dutile /** 11085a8eb242SAlexander Duyck * pci_vfs_assigned - returns number of VFs are assigned to a guest 11095a8eb242SAlexander Duyck * @dev: the PCI device 11105a8eb242SAlexander Duyck * 11115a8eb242SAlexander Duyck * Returns number of VFs belonging to this device that are assigned to a guest. 1112652d1100SStefan Assmann * If device is not a physical function returns 0. 11135a8eb242SAlexander Duyck */ 11145a8eb242SAlexander Duyck int pci_vfs_assigned(struct pci_dev *dev) 11155a8eb242SAlexander Duyck { 11165a8eb242SAlexander Duyck struct pci_dev *vfdev; 11175a8eb242SAlexander Duyck unsigned int vfs_assigned = 0; 11185a8eb242SAlexander Duyck unsigned short dev_id; 11195a8eb242SAlexander Duyck 11205a8eb242SAlexander Duyck /* only search if we are a PF */ 11215a8eb242SAlexander Duyck if (!dev->is_physfn) 11225a8eb242SAlexander Duyck return 0; 11235a8eb242SAlexander Duyck 11245a8eb242SAlexander Duyck /* 11255a8eb242SAlexander Duyck * determine the device ID for the VFs, the vendor ID will be the 11265a8eb242SAlexander Duyck * same as the PF so there is no need to check for that one 11275a8eb242SAlexander Duyck */ 11283142d832SFilippo Sironi dev_id = dev->sriov->vf_device; 11295a8eb242SAlexander Duyck 11305a8eb242SAlexander Duyck /* loop through all the VFs to see if we own any that are assigned */ 11315a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, NULL); 11325a8eb242SAlexander Duyck while (vfdev) { 11335a8eb242SAlexander Duyck /* 11345a8eb242SAlexander Duyck * It is considered assigned if it is a virtual function with 11355a8eb242SAlexander Duyck * our dev as the physical function and the assigned bit is set 11365a8eb242SAlexander Duyck */ 11375a8eb242SAlexander Duyck if (vfdev->is_virtfn && (vfdev->physfn == dev) && 1138be63497cSEthan Zhao pci_is_dev_assigned(vfdev)) 11395a8eb242SAlexander Duyck vfs_assigned++; 11405a8eb242SAlexander Duyck 11415a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, vfdev); 11425a8eb242SAlexander Duyck } 11435a8eb242SAlexander Duyck 11445a8eb242SAlexander Duyck return vfs_assigned; 11455a8eb242SAlexander Duyck } 11465a8eb242SAlexander Duyck EXPORT_SYMBOL_GPL(pci_vfs_assigned); 11475a8eb242SAlexander Duyck 11485a8eb242SAlexander Duyck /** 1149bff73156SDonald Dutile * pci_sriov_set_totalvfs -- reduce the TotalVFs available 1150bff73156SDonald Dutile * @dev: the PCI PF device 11512094f167SRandy Dunlap * @numvfs: number that should be used for TotalVFs supported 1152bff73156SDonald Dutile * 1153bff73156SDonald Dutile * Should be called from PF driver's probe routine with 1154bff73156SDonald Dutile * device's mutex held. 1155bff73156SDonald Dutile * 1156bff73156SDonald Dutile * Returns 0 if PF is an SRIOV-capable device and 1157652d1100SStefan Assmann * value of numvfs valid. If not a PF return -ENOSYS; 1158652d1100SStefan Assmann * if numvfs is invalid return -EINVAL; 1159bff73156SDonald Dutile * if VFs already enabled, return -EBUSY. 1160bff73156SDonald Dutile */ 1161bff73156SDonald Dutile int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) 1162bff73156SDonald Dutile { 1163652d1100SStefan Assmann if (!dev->is_physfn) 1164652d1100SStefan Assmann return -ENOSYS; 116551259d00SBjorn Helgaas 1166652d1100SStefan Assmann if (numvfs > dev->sriov->total_VFs) 1167bff73156SDonald Dutile return -EINVAL; 1168bff73156SDonald Dutile 1169bff73156SDonald Dutile /* Shouldn't change if VFs already enabled */ 1170bff73156SDonald Dutile if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) 1171bff73156SDonald Dutile return -EBUSY; 1172bff73156SDonald Dutile 117351259d00SBjorn Helgaas dev->sriov->driver_max_VFs = numvfs; 1174bff73156SDonald Dutile return 0; 1175bff73156SDonald Dutile } 1176bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); 1177bff73156SDonald Dutile 1178bff73156SDonald Dutile /** 1179ddc191f5SJonghwan Choi * pci_sriov_get_totalvfs -- get total VFs supported on this device 1180bff73156SDonald Dutile * @dev: the PCI PF device 1181bff73156SDonald Dutile * 1182bff73156SDonald Dutile * For a PCIe device with SRIOV support, return the PCIe 11836b136724SBjorn Helgaas * SRIOV capability value of TotalVFs or the value of driver_max_VFs 1184652d1100SStefan Assmann * if the driver reduced it. Otherwise 0. 1185bff73156SDonald Dutile */ 1186bff73156SDonald Dutile int pci_sriov_get_totalvfs(struct pci_dev *dev) 1187bff73156SDonald Dutile { 11881452cd76SBjorn Helgaas if (!dev->is_physfn) 1189652d1100SStefan Assmann return 0; 1190bff73156SDonald Dutile 11916b136724SBjorn Helgaas return dev->sriov->driver_max_VFs; 1192bff73156SDonald Dutile } 1193bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); 11948effc395SAlexander Duyck 11958effc395SAlexander Duyck /** 11968effc395SAlexander Duyck * pci_sriov_configure_simple - helper to configure SR-IOV 11978effc395SAlexander Duyck * @dev: the PCI device 11988effc395SAlexander Duyck * @nr_virtfn: number of virtual functions to enable, 0 to disable 11998effc395SAlexander Duyck * 12008effc395SAlexander Duyck * Enable or disable SR-IOV for devices that don't require any PF setup 12018effc395SAlexander Duyck * before enabling SR-IOV. Return value is negative on error, or number of 12028effc395SAlexander Duyck * VFs allocated on success. 12038effc395SAlexander Duyck */ 12048effc395SAlexander Duyck int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn) 12058effc395SAlexander Duyck { 12068effc395SAlexander Duyck int rc; 12078effc395SAlexander Duyck 12088effc395SAlexander Duyck might_sleep(); 12098effc395SAlexander Duyck 12108effc395SAlexander Duyck if (!dev->is_physfn) 12118effc395SAlexander Duyck return -ENODEV; 12128effc395SAlexander Duyck 12138effc395SAlexander Duyck if (pci_vfs_assigned(dev)) { 12148effc395SAlexander Duyck pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n"); 12158effc395SAlexander Duyck return -EPERM; 12168effc395SAlexander Duyck } 12178effc395SAlexander Duyck 12188effc395SAlexander Duyck if (nr_virtfn == 0) { 12198effc395SAlexander Duyck sriov_disable(dev); 12208effc395SAlexander Duyck return 0; 12218effc395SAlexander Duyck } 12228effc395SAlexander Duyck 12238effc395SAlexander Duyck rc = sriov_enable(dev, nr_virtfn); 12248effc395SAlexander Duyck if (rc < 0) 12258effc395SAlexander Duyck return rc; 12268effc395SAlexander Duyck 12278effc395SAlexander Duyck return nr_virtfn; 12288effc395SAlexander Duyck } 12298effc395SAlexander Duyck EXPORT_SYMBOL_GPL(pci_sriov_configure_simple); 1230