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 17dd7cc44dSYu Zhao #define VIRTFN_ID_LEN 16 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 36f59dca27SWei Yang /* 37f59dca27SWei Yang * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may 38f59dca27SWei Yang * change when NumVFs changes. 39f59dca27SWei Yang * 40f59dca27SWei Yang * Update iov->offset and iov->stride when NumVFs is written. 41f59dca27SWei Yang */ 42f59dca27SWei Yang static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn) 43f59dca27SWei Yang { 44f59dca27SWei Yang struct pci_sriov *iov = dev->sriov; 45f59dca27SWei Yang 46f59dca27SWei Yang pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); 47f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 48f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 49f59dca27SWei Yang } 50f59dca27SWei Yang 514449f079SWei Yang /* 524449f079SWei Yang * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride 534449f079SWei Yang * determine how many additional bus numbers will be consumed by VFs. 544449f079SWei Yang * 55ea9a8854SAlexander Duyck * Iterate over all valid NumVFs, validate offset and stride, and calculate 56ea9a8854SAlexander Duyck * the maximum number of bus numbers that could ever be required. 574449f079SWei Yang */ 58ea9a8854SAlexander Duyck static int compute_max_vf_buses(struct pci_dev *dev) 594449f079SWei Yang { 604449f079SWei Yang struct pci_sriov *iov = dev->sriov; 61ea9a8854SAlexander Duyck int nr_virtfn, busnr, rc = 0; 624449f079SWei Yang 63ea9a8854SAlexander Duyck for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) { 644449f079SWei Yang pci_iov_set_numvfs(dev, nr_virtfn); 65ea9a8854SAlexander Duyck if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) { 66ea9a8854SAlexander Duyck rc = -EIO; 67ea9a8854SAlexander Duyck goto out; 684449f079SWei Yang } 694449f079SWei Yang 70ea9a8854SAlexander Duyck busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 71ea9a8854SAlexander Duyck if (busnr > iov->max_VF_buses) 72ea9a8854SAlexander Duyck iov->max_VF_buses = busnr; 73ea9a8854SAlexander Duyck } 74ea9a8854SAlexander Duyck 75ea9a8854SAlexander Duyck out: 76ea9a8854SAlexander Duyck pci_iov_set_numvfs(dev, 0); 77ea9a8854SAlexander Duyck return rc; 784449f079SWei Yang } 794449f079SWei Yang 80dd7cc44dSYu Zhao static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) 81dd7cc44dSYu Zhao { 82dd7cc44dSYu Zhao struct pci_bus *child; 83dd7cc44dSYu Zhao 84dd7cc44dSYu Zhao if (bus->number == busnr) 85dd7cc44dSYu Zhao return bus; 86dd7cc44dSYu Zhao 87dd7cc44dSYu Zhao child = pci_find_bus(pci_domain_nr(bus), busnr); 88dd7cc44dSYu Zhao if (child) 89dd7cc44dSYu Zhao return child; 90dd7cc44dSYu Zhao 91dd7cc44dSYu Zhao child = pci_add_new_bus(bus, NULL, busnr); 92dd7cc44dSYu Zhao if (!child) 93dd7cc44dSYu Zhao return NULL; 94dd7cc44dSYu Zhao 95b7eac055SYinghai Lu pci_bus_insert_busn_res(child, busnr, busnr); 96dd7cc44dSYu Zhao 97dd7cc44dSYu Zhao return child; 98dd7cc44dSYu Zhao } 99dd7cc44dSYu Zhao 100dc087f2fSJiang Liu static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus) 101dd7cc44dSYu Zhao { 102dc087f2fSJiang Liu if (physbus != virtbus && list_empty(&virtbus->devices)) 103dc087f2fSJiang Liu pci_remove_bus(virtbus); 104dd7cc44dSYu Zhao } 105dd7cc44dSYu Zhao 1060e6c9122SWei Yang resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) 1070e6c9122SWei Yang { 1080e6c9122SWei Yang if (!dev->is_physfn) 1090e6c9122SWei Yang return 0; 1100e6c9122SWei Yang 1110e6c9122SWei Yang return dev->sriov->barsz[resno - PCI_IOV_RESOURCES]; 1120e6c9122SWei Yang } 1130e6c9122SWei Yang 114cf0921beSKarimAllah Ahmed static void pci_read_vf_config_common(struct pci_dev *virtfn) 115cf0921beSKarimAllah Ahmed { 116cf0921beSKarimAllah Ahmed struct pci_dev *physfn = virtfn->physfn; 117cf0921beSKarimAllah Ahmed 118cf0921beSKarimAllah Ahmed /* 119cf0921beSKarimAllah Ahmed * Some config registers are the same across all associated VFs. 120cf0921beSKarimAllah Ahmed * Read them once from VF0 so we can skip reading them from the 121cf0921beSKarimAllah Ahmed * other VFs. 122cf0921beSKarimAllah Ahmed * 123cf0921beSKarimAllah Ahmed * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to 124cf0921beSKarimAllah Ahmed * have the same Revision ID and Subsystem ID, but we assume they 125cf0921beSKarimAllah Ahmed * do. 126cf0921beSKarimAllah Ahmed */ 127cf0921beSKarimAllah Ahmed pci_read_config_dword(virtfn, PCI_CLASS_REVISION, 128cf0921beSKarimAllah Ahmed &physfn->sriov->class); 129cf0921beSKarimAllah Ahmed pci_read_config_byte(virtfn, PCI_HEADER_TYPE, 130cf0921beSKarimAllah Ahmed &physfn->sriov->hdr_type); 131cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID, 132cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_vendor); 133cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID, 134cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_device); 135cf0921beSKarimAllah Ahmed } 136cf0921beSKarimAllah Ahmed 137a1ceea67SNiklas Schnelle int pci_iov_sysfs_link(struct pci_dev *dev, 138a1ceea67SNiklas Schnelle struct pci_dev *virtfn, int id) 139a1ceea67SNiklas Schnelle { 140a1ceea67SNiklas Schnelle char buf[VIRTFN_ID_LEN]; 141a1ceea67SNiklas Schnelle int rc; 142a1ceea67SNiklas Schnelle 143a1ceea67SNiklas Schnelle sprintf(buf, "virtfn%u", id); 144a1ceea67SNiklas Schnelle rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); 145a1ceea67SNiklas Schnelle if (rc) 146a1ceea67SNiklas Schnelle goto failed; 147a1ceea67SNiklas Schnelle rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn"); 148a1ceea67SNiklas Schnelle if (rc) 149a1ceea67SNiklas Schnelle goto failed1; 150a1ceea67SNiklas Schnelle 151a1ceea67SNiklas Schnelle kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); 152a1ceea67SNiklas Schnelle 153a1ceea67SNiklas Schnelle return 0; 154a1ceea67SNiklas Schnelle 155a1ceea67SNiklas Schnelle failed1: 156a1ceea67SNiklas Schnelle sysfs_remove_link(&dev->dev.kobj, buf); 157a1ceea67SNiklas Schnelle failed: 158a1ceea67SNiklas Schnelle return rc; 159a1ceea67SNiklas Schnelle } 160a1ceea67SNiklas Schnelle 161c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 162c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_total_msix_show(struct device *dev, 163c3d5c2d9SLeon Romanovsky struct device_attribute *attr, 164c3d5c2d9SLeon Romanovsky char *buf) 165c3d5c2d9SLeon Romanovsky { 166c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev); 167c3d5c2d9SLeon Romanovsky u32 vf_total_msix = 0; 168c3d5c2d9SLeon Romanovsky 169c3d5c2d9SLeon Romanovsky device_lock(dev); 170c3d5c2d9SLeon Romanovsky if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix) 171c3d5c2d9SLeon Romanovsky goto unlock; 172c3d5c2d9SLeon Romanovsky 173c3d5c2d9SLeon Romanovsky vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev); 174c3d5c2d9SLeon Romanovsky unlock: 175c3d5c2d9SLeon Romanovsky device_unlock(dev); 176c3d5c2d9SLeon Romanovsky return sysfs_emit(buf, "%u\n", vf_total_msix); 177c3d5c2d9SLeon Romanovsky } 178c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_RO(sriov_vf_total_msix); 179c3d5c2d9SLeon Romanovsky 180c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_msix_count_store(struct device *dev, 181c3d5c2d9SLeon Romanovsky struct device_attribute *attr, 182c3d5c2d9SLeon Romanovsky const char *buf, size_t count) 183c3d5c2d9SLeon Romanovsky { 184c3d5c2d9SLeon Romanovsky struct pci_dev *vf_dev = to_pci_dev(dev); 185c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = pci_physfn(vf_dev); 186*36f354ecSKrzysztof Wilczyński int val, ret = 0; 187c3d5c2d9SLeon Romanovsky 188*36f354ecSKrzysztof Wilczyński if (kstrtoint(buf, 0, &val) < 0) 189*36f354ecSKrzysztof Wilczyński return -EINVAL; 190c3d5c2d9SLeon Romanovsky 191c3d5c2d9SLeon Romanovsky if (val < 0) 192c3d5c2d9SLeon Romanovsky return -EINVAL; 193c3d5c2d9SLeon Romanovsky 194c3d5c2d9SLeon Romanovsky device_lock(&pdev->dev); 195c3d5c2d9SLeon Romanovsky if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) { 196c3d5c2d9SLeon Romanovsky ret = -EOPNOTSUPP; 197c3d5c2d9SLeon Romanovsky goto err_pdev; 198c3d5c2d9SLeon Romanovsky } 199c3d5c2d9SLeon Romanovsky 200c3d5c2d9SLeon Romanovsky device_lock(&vf_dev->dev); 201c3d5c2d9SLeon Romanovsky if (vf_dev->driver) { 202c3d5c2d9SLeon Romanovsky /* 203c3d5c2d9SLeon Romanovsky * A driver is already attached to this VF and has configured 204c3d5c2d9SLeon Romanovsky * itself based on the current MSI-X vector count. Changing 205c3d5c2d9SLeon Romanovsky * the vector size could mess up the driver, so block it. 206c3d5c2d9SLeon Romanovsky */ 207c3d5c2d9SLeon Romanovsky ret = -EBUSY; 208c3d5c2d9SLeon Romanovsky goto err_dev; 209c3d5c2d9SLeon Romanovsky } 210c3d5c2d9SLeon Romanovsky 211c3d5c2d9SLeon Romanovsky ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val); 212c3d5c2d9SLeon Romanovsky 213c3d5c2d9SLeon Romanovsky err_dev: 214c3d5c2d9SLeon Romanovsky device_unlock(&vf_dev->dev); 215c3d5c2d9SLeon Romanovsky err_pdev: 216c3d5c2d9SLeon Romanovsky device_unlock(&pdev->dev); 217c3d5c2d9SLeon Romanovsky return ret ? : count; 218c3d5c2d9SLeon Romanovsky } 219c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_WO(sriov_vf_msix_count); 220c3d5c2d9SLeon Romanovsky #endif 221c3d5c2d9SLeon Romanovsky 222c3d5c2d9SLeon Romanovsky static struct attribute *sriov_vf_dev_attrs[] = { 223c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 224c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_msix_count.attr, 225c3d5c2d9SLeon Romanovsky #endif 226c3d5c2d9SLeon Romanovsky NULL, 227c3d5c2d9SLeon Romanovsky }; 228c3d5c2d9SLeon Romanovsky 229c3d5c2d9SLeon Romanovsky static umode_t sriov_vf_attrs_are_visible(struct kobject *kobj, 230c3d5c2d9SLeon Romanovsky struct attribute *a, int n) 231c3d5c2d9SLeon Romanovsky { 232c3d5c2d9SLeon Romanovsky struct device *dev = kobj_to_dev(kobj); 233c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev); 234c3d5c2d9SLeon Romanovsky 235c3d5c2d9SLeon Romanovsky if (!pdev->is_virtfn) 236c3d5c2d9SLeon Romanovsky return 0; 237c3d5c2d9SLeon Romanovsky 238c3d5c2d9SLeon Romanovsky return a->mode; 239c3d5c2d9SLeon Romanovsky } 240c3d5c2d9SLeon Romanovsky 241c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_vf_dev_attr_group = { 242c3d5c2d9SLeon Romanovsky .attrs = sriov_vf_dev_attrs, 243c3d5c2d9SLeon Romanovsky .is_visible = sriov_vf_attrs_are_visible, 244c3d5c2d9SLeon Romanovsky }; 245c3d5c2d9SLeon Romanovsky 246753f6124SJan H. Schönherr int pci_iov_add_virtfn(struct pci_dev *dev, int id) 247dd7cc44dSYu Zhao { 248dd7cc44dSYu Zhao int i; 249dc087f2fSJiang Liu int rc = -ENOMEM; 250dd7cc44dSYu Zhao u64 size; 251dd7cc44dSYu Zhao struct pci_dev *virtfn; 252dd7cc44dSYu Zhao struct resource *res; 253dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 2548b1fce04SGu Zheng struct pci_bus *bus; 255dd7cc44dSYu Zhao 256b07579c0SWei Yang bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id)); 257dc087f2fSJiang Liu if (!bus) 258dc087f2fSJiang Liu goto failed; 259dc087f2fSJiang Liu 260dc087f2fSJiang Liu virtfn = pci_alloc_dev(bus); 261dc087f2fSJiang Liu if (!virtfn) 262dc087f2fSJiang Liu goto failed0; 263dc087f2fSJiang Liu 264b07579c0SWei Yang virtfn->devfn = pci_iov_virtfn_devfn(dev, id); 265dd7cc44dSYu Zhao virtfn->vendor = dev->vendor; 2663142d832SFilippo Sironi virtfn->device = iov->vf_device; 267cf0921beSKarimAllah Ahmed virtfn->is_virtfn = 1; 268cf0921beSKarimAllah Ahmed virtfn->physfn = pci_dev_get(dev); 26912856e7aSMatthew Rosato virtfn->no_command_memory = 1; 270cf0921beSKarimAllah Ahmed 271cf0921beSKarimAllah Ahmed if (id == 0) 272cf0921beSKarimAllah Ahmed pci_read_vf_config_common(virtfn); 273cf0921beSKarimAllah Ahmed 274156c5532SPo Liu rc = pci_setup_device(virtfn); 275156c5532SPo Liu if (rc) 276cf0921beSKarimAllah Ahmed goto failed1; 277156c5532SPo Liu 278dd7cc44dSYu Zhao virtfn->dev.parent = dev->dev.parent; 279aa931977SAlex Williamson virtfn->multifunction = 0; 280dd7cc44dSYu Zhao 281dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 282c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 283dd7cc44dSYu Zhao if (!res->parent) 284dd7cc44dSYu Zhao continue; 285dd7cc44dSYu Zhao virtfn->resource[i].name = pci_name(virtfn); 286dd7cc44dSYu Zhao virtfn->resource[i].flags = res->flags; 2870e6c9122SWei Yang size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES); 288dd7cc44dSYu Zhao virtfn->resource[i].start = res->start + size * id; 289dd7cc44dSYu Zhao virtfn->resource[i].end = virtfn->resource[i].start + size - 1; 290dd7cc44dSYu Zhao rc = request_resource(res, &virtfn->resource[i]); 291dd7cc44dSYu Zhao BUG_ON(rc); 292dd7cc44dSYu Zhao } 293dd7cc44dSYu Zhao 294dd7cc44dSYu Zhao pci_device_add(virtfn, virtfn->bus); 295a1ceea67SNiklas Schnelle rc = pci_iov_sysfs_link(dev, virtfn, id); 296dd7cc44dSYu Zhao if (rc) 2978c386cc8SNavid Emamdoost goto failed1; 298dd7cc44dSYu Zhao 29927d61629SStuart Hayes pci_bus_add_device(virtfn); 30027d61629SStuart Hayes 301dd7cc44dSYu Zhao return 0; 302dd7cc44dSYu Zhao 303dd7cc44dSYu Zhao failed1: 3048c386cc8SNavid Emamdoost pci_stop_and_remove_bus_device(virtfn); 305dd7cc44dSYu Zhao pci_dev_put(dev); 306dc087f2fSJiang Liu failed0: 307dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, bus); 308dc087f2fSJiang Liu failed: 309dd7cc44dSYu Zhao 310dd7cc44dSYu Zhao return rc; 311dd7cc44dSYu Zhao } 312dd7cc44dSYu Zhao 313753f6124SJan H. Schönherr void pci_iov_remove_virtfn(struct pci_dev *dev, int id) 314dd7cc44dSYu Zhao { 315dd7cc44dSYu Zhao char buf[VIRTFN_ID_LEN]; 316dd7cc44dSYu Zhao struct pci_dev *virtfn; 317dd7cc44dSYu Zhao 318dc087f2fSJiang Liu virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), 319b07579c0SWei Yang pci_iov_virtfn_bus(dev, id), 320b07579c0SWei Yang pci_iov_virtfn_devfn(dev, id)); 321dd7cc44dSYu Zhao if (!virtfn) 322dd7cc44dSYu Zhao return; 323dd7cc44dSYu Zhao 324dd7cc44dSYu Zhao sprintf(buf, "virtfn%u", id); 325dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, buf); 32609cedbefSYinghai Lu /* 32709cedbefSYinghai Lu * pci_stop_dev() could have been called for this virtfn already, 32809cedbefSYinghai Lu * so the directory for the virtfn may have been removed before. 32909cedbefSYinghai Lu * Double check to avoid spurious sysfs warnings. 33009cedbefSYinghai Lu */ 33109cedbefSYinghai Lu if (virtfn->dev.kobj.sd) 332dd7cc44dSYu Zhao sysfs_remove_link(&virtfn->dev.kobj, "physfn"); 333dd7cc44dSYu Zhao 334210647afSYinghai Lu pci_stop_and_remove_bus_device(virtfn); 335dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, virtfn->bus); 336dd7cc44dSYu Zhao 337dc087f2fSJiang Liu /* balance pci_get_domain_bus_and_slot() */ 338dc087f2fSJiang Liu pci_dev_put(virtfn); 339dd7cc44dSYu Zhao pci_dev_put(dev); 340dd7cc44dSYu Zhao } 341dd7cc44dSYu Zhao 342aaee0c1fSKelsey Skunberg static ssize_t sriov_totalvfs_show(struct device *dev, 343aaee0c1fSKelsey Skunberg struct device_attribute *attr, 344aaee0c1fSKelsey Skunberg char *buf) 345aaee0c1fSKelsey Skunberg { 346aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 347aaee0c1fSKelsey Skunberg 348f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); 349aaee0c1fSKelsey Skunberg } 350aaee0c1fSKelsey Skunberg 351aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_show(struct device *dev, 352aaee0c1fSKelsey Skunberg struct device_attribute *attr, 353aaee0c1fSKelsey Skunberg char *buf) 354aaee0c1fSKelsey Skunberg { 355aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 35635ff867bSPierre Crégut u16 num_vfs; 357aaee0c1fSKelsey Skunberg 35835ff867bSPierre Crégut /* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */ 35935ff867bSPierre Crégut device_lock(&pdev->dev); 36035ff867bSPierre Crégut num_vfs = pdev->sriov->num_VFs; 36135ff867bSPierre Crégut device_unlock(&pdev->dev); 36235ff867bSPierre Crégut 363f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", num_vfs); 364aaee0c1fSKelsey Skunberg } 365aaee0c1fSKelsey Skunberg 366aaee0c1fSKelsey Skunberg /* 367aaee0c1fSKelsey Skunberg * num_vfs > 0; number of VFs to enable 368aaee0c1fSKelsey Skunberg * num_vfs = 0; disable all VFs 369aaee0c1fSKelsey Skunberg * 370aaee0c1fSKelsey Skunberg * Note: SRIOV spec does not allow partial VF 371aaee0c1fSKelsey Skunberg * disable, so it's all or none. 372aaee0c1fSKelsey Skunberg */ 373aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_store(struct device *dev, 374aaee0c1fSKelsey Skunberg struct device_attribute *attr, 375aaee0c1fSKelsey Skunberg const char *buf, size_t count) 376aaee0c1fSKelsey Skunberg { 377aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 378*36f354ecSKrzysztof Wilczyński int ret = 0; 379aaee0c1fSKelsey Skunberg u16 num_vfs; 380aaee0c1fSKelsey Skunberg 381*36f354ecSKrzysztof Wilczyński if (kstrtou16(buf, 0, &num_vfs) < 0) 382*36f354ecSKrzysztof Wilczyński return -EINVAL; 383aaee0c1fSKelsey Skunberg 384aaee0c1fSKelsey Skunberg if (num_vfs > pci_sriov_get_totalvfs(pdev)) 385aaee0c1fSKelsey Skunberg return -ERANGE; 386aaee0c1fSKelsey Skunberg 387aaee0c1fSKelsey Skunberg device_lock(&pdev->dev); 388aaee0c1fSKelsey Skunberg 389aaee0c1fSKelsey Skunberg if (num_vfs == pdev->sriov->num_VFs) 390aaee0c1fSKelsey Skunberg goto exit; 391aaee0c1fSKelsey Skunberg 392e9c3bbd6SMoritz Fischer /* is PF driver loaded */ 393e9c3bbd6SMoritz Fischer if (!pdev->driver) { 394e9c3bbd6SMoritz Fischer pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n"); 395e9c3bbd6SMoritz Fischer ret = -ENOENT; 396e9c3bbd6SMoritz Fischer goto exit; 397e9c3bbd6SMoritz Fischer } 398e9c3bbd6SMoritz Fischer 399aaee0c1fSKelsey Skunberg /* is PF driver loaded w/callback */ 400e9c3bbd6SMoritz Fischer if (!pdev->driver->sriov_configure) { 401e9c3bbd6SMoritz Fischer pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n"); 402aaee0c1fSKelsey Skunberg ret = -ENOENT; 403aaee0c1fSKelsey Skunberg goto exit; 404aaee0c1fSKelsey Skunberg } 405aaee0c1fSKelsey Skunberg 406aaee0c1fSKelsey Skunberg if (num_vfs == 0) { 407aaee0c1fSKelsey Skunberg /* disable VFs */ 408aaee0c1fSKelsey Skunberg ret = pdev->driver->sriov_configure(pdev, 0); 409aaee0c1fSKelsey Skunberg goto exit; 410aaee0c1fSKelsey Skunberg } 411aaee0c1fSKelsey Skunberg 412aaee0c1fSKelsey Skunberg /* enable VFs */ 413aaee0c1fSKelsey Skunberg if (pdev->sriov->num_VFs) { 414aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n", 415aaee0c1fSKelsey Skunberg pdev->sriov->num_VFs, num_vfs); 416aaee0c1fSKelsey Skunberg ret = -EBUSY; 417aaee0c1fSKelsey Skunberg goto exit; 418aaee0c1fSKelsey Skunberg } 419aaee0c1fSKelsey Skunberg 420aaee0c1fSKelsey Skunberg ret = pdev->driver->sriov_configure(pdev, num_vfs); 421aaee0c1fSKelsey Skunberg if (ret < 0) 422aaee0c1fSKelsey Skunberg goto exit; 423aaee0c1fSKelsey Skunberg 424aaee0c1fSKelsey Skunberg if (ret != num_vfs) 425aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs requested; only %d enabled\n", 426aaee0c1fSKelsey Skunberg num_vfs, ret); 427aaee0c1fSKelsey Skunberg 428aaee0c1fSKelsey Skunberg exit: 429aaee0c1fSKelsey Skunberg device_unlock(&pdev->dev); 430aaee0c1fSKelsey Skunberg 431aaee0c1fSKelsey Skunberg if (ret < 0) 432aaee0c1fSKelsey Skunberg return ret; 433aaee0c1fSKelsey Skunberg 434aaee0c1fSKelsey Skunberg return count; 435aaee0c1fSKelsey Skunberg } 436aaee0c1fSKelsey Skunberg 437aaee0c1fSKelsey Skunberg static ssize_t sriov_offset_show(struct device *dev, 438aaee0c1fSKelsey Skunberg struct device_attribute *attr, 439aaee0c1fSKelsey Skunberg char *buf) 440aaee0c1fSKelsey Skunberg { 441aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 442aaee0c1fSKelsey Skunberg 443f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->offset); 444aaee0c1fSKelsey Skunberg } 445aaee0c1fSKelsey Skunberg 446aaee0c1fSKelsey Skunberg static ssize_t sriov_stride_show(struct device *dev, 447aaee0c1fSKelsey Skunberg struct device_attribute *attr, 448aaee0c1fSKelsey Skunberg char *buf) 449aaee0c1fSKelsey Skunberg { 450aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 451aaee0c1fSKelsey Skunberg 452f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->stride); 453aaee0c1fSKelsey Skunberg } 454aaee0c1fSKelsey Skunberg 455aaee0c1fSKelsey Skunberg static ssize_t sriov_vf_device_show(struct device *dev, 456aaee0c1fSKelsey Skunberg struct device_attribute *attr, 457aaee0c1fSKelsey Skunberg char *buf) 458aaee0c1fSKelsey Skunberg { 459aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 460aaee0c1fSKelsey Skunberg 461f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device); 462aaee0c1fSKelsey Skunberg } 463aaee0c1fSKelsey Skunberg 464aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_show(struct device *dev, 465aaee0c1fSKelsey Skunberg struct device_attribute *attr, 466aaee0c1fSKelsey Skunberg char *buf) 467aaee0c1fSKelsey Skunberg { 468aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 469aaee0c1fSKelsey Skunberg 470f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe); 471aaee0c1fSKelsey Skunberg } 472aaee0c1fSKelsey Skunberg 473aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_store(struct device *dev, 474aaee0c1fSKelsey Skunberg struct device_attribute *attr, 475aaee0c1fSKelsey Skunberg const char *buf, size_t count) 476aaee0c1fSKelsey Skunberg { 477aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 478aaee0c1fSKelsey Skunberg bool drivers_autoprobe; 479aaee0c1fSKelsey Skunberg 480aaee0c1fSKelsey Skunberg if (kstrtobool(buf, &drivers_autoprobe) < 0) 481aaee0c1fSKelsey Skunberg return -EINVAL; 482aaee0c1fSKelsey Skunberg 483aaee0c1fSKelsey Skunberg pdev->sriov->drivers_autoprobe = drivers_autoprobe; 484aaee0c1fSKelsey Skunberg 485aaee0c1fSKelsey Skunberg return count; 486aaee0c1fSKelsey Skunberg } 487aaee0c1fSKelsey Skunberg 488aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_totalvfs); 489244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_numvfs); 490aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_offset); 491aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_stride); 492aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_vf_device); 493244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_drivers_autoprobe); 494aaee0c1fSKelsey Skunberg 495c3d5c2d9SLeon Romanovsky static struct attribute *sriov_pf_dev_attrs[] = { 496aaee0c1fSKelsey Skunberg &dev_attr_sriov_totalvfs.attr, 497aaee0c1fSKelsey Skunberg &dev_attr_sriov_numvfs.attr, 498aaee0c1fSKelsey Skunberg &dev_attr_sriov_offset.attr, 499aaee0c1fSKelsey Skunberg &dev_attr_sriov_stride.attr, 500aaee0c1fSKelsey Skunberg &dev_attr_sriov_vf_device.attr, 501aaee0c1fSKelsey Skunberg &dev_attr_sriov_drivers_autoprobe.attr, 502c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI 503c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_total_msix.attr, 504c3d5c2d9SLeon Romanovsky #endif 505aaee0c1fSKelsey Skunberg NULL, 506aaee0c1fSKelsey Skunberg }; 507aaee0c1fSKelsey Skunberg 508c3d5c2d9SLeon Romanovsky static umode_t sriov_pf_attrs_are_visible(struct kobject *kobj, 509aaee0c1fSKelsey Skunberg struct attribute *a, int n) 510aaee0c1fSKelsey Skunberg { 511aaee0c1fSKelsey Skunberg struct device *dev = kobj_to_dev(kobj); 512aaee0c1fSKelsey Skunberg 513aaee0c1fSKelsey Skunberg if (!dev_is_pf(dev)) 514aaee0c1fSKelsey Skunberg return 0; 515aaee0c1fSKelsey Skunberg 516aaee0c1fSKelsey Skunberg return a->mode; 517aaee0c1fSKelsey Skunberg } 518aaee0c1fSKelsey Skunberg 519c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_pf_dev_attr_group = { 520c3d5c2d9SLeon Romanovsky .attrs = sriov_pf_dev_attrs, 521c3d5c2d9SLeon Romanovsky .is_visible = sriov_pf_attrs_are_visible, 522aaee0c1fSKelsey Skunberg }; 523aaee0c1fSKelsey Skunberg 524995df527SWei Yang int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs) 525995df527SWei Yang { 526995df527SWei Yang return 0; 527995df527SWei Yang } 528995df527SWei Yang 529a39e3fcdSAlexander Duyck int __weak pcibios_sriov_disable(struct pci_dev *pdev) 530a39e3fcdSAlexander Duyck { 531a39e3fcdSAlexander Duyck return 0; 532a39e3fcdSAlexander Duyck } 533a39e3fcdSAlexander Duyck 53418f9e9d1SSebastian Ott static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) 53518f9e9d1SSebastian Ott { 53618f9e9d1SSebastian Ott unsigned int i; 53718f9e9d1SSebastian Ott int rc; 53818f9e9d1SSebastian Ott 539aff68a5aSSebastian Ott if (dev->no_vf_scan) 540aff68a5aSSebastian Ott return 0; 541aff68a5aSSebastian Ott 54218f9e9d1SSebastian Ott for (i = 0; i < num_vfs; i++) { 54318f9e9d1SSebastian Ott rc = pci_iov_add_virtfn(dev, i); 54418f9e9d1SSebastian Ott if (rc) 54518f9e9d1SSebastian Ott goto failed; 54618f9e9d1SSebastian Ott } 54718f9e9d1SSebastian Ott return 0; 54818f9e9d1SSebastian Ott failed: 54918f9e9d1SSebastian Ott while (i--) 55018f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 55118f9e9d1SSebastian Ott 55218f9e9d1SSebastian Ott return rc; 55318f9e9d1SSebastian Ott } 55418f9e9d1SSebastian Ott 555dd7cc44dSYu Zhao static int sriov_enable(struct pci_dev *dev, int nr_virtfn) 556dd7cc44dSYu Zhao { 557dd7cc44dSYu Zhao int rc; 5583443c382SAlexander Duyck int i; 559dd7cc44dSYu Zhao int nres; 560ce288ec3SAlexander Duyck u16 initial; 561dd7cc44dSYu Zhao struct resource *res; 562dd7cc44dSYu Zhao struct pci_dev *pdev; 563dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 564bbef98abSRam Pai int bars = 0; 565b07579c0SWei Yang int bus; 566dd7cc44dSYu Zhao 567dd7cc44dSYu Zhao if (!nr_virtfn) 568dd7cc44dSYu Zhao return 0; 569dd7cc44dSYu Zhao 5706b136724SBjorn Helgaas if (iov->num_VFs) 571dd7cc44dSYu Zhao return -EINVAL; 572dd7cc44dSYu Zhao 573dd7cc44dSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); 5746b136724SBjorn Helgaas if (initial > iov->total_VFs || 5756b136724SBjorn Helgaas (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs))) 576dd7cc44dSYu Zhao return -EIO; 577dd7cc44dSYu Zhao 5786b136724SBjorn Helgaas if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs || 579dd7cc44dSYu Zhao (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) 580dd7cc44dSYu Zhao return -EINVAL; 581dd7cc44dSYu Zhao 582dd7cc44dSYu Zhao nres = 0; 583dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 584bbef98abSRam Pai bars |= (1 << (i + PCI_IOV_RESOURCES)); 585c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 586dd7cc44dSYu Zhao if (res->parent) 587dd7cc44dSYu Zhao nres++; 588dd7cc44dSYu Zhao } 589dd7cc44dSYu Zhao if (nres != iov->nres) { 5907506dc79SFrederick Lawler pci_err(dev, "not enough MMIO resources for SR-IOV\n"); 591dd7cc44dSYu Zhao return -ENOMEM; 592dd7cc44dSYu Zhao } 593dd7cc44dSYu Zhao 594b07579c0SWei Yang bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 59568f8e9faSBjorn Helgaas if (bus > dev->bus->busn_res.end) { 5967506dc79SFrederick Lawler pci_err(dev, "can't enable %d VFs (bus %02x out of range of %pR)\n", 59768f8e9faSBjorn Helgaas nr_virtfn, bus, &dev->bus->busn_res); 598dd7cc44dSYu Zhao return -ENOMEM; 599dd7cc44dSYu Zhao } 600dd7cc44dSYu Zhao 601bbef98abSRam Pai if (pci_enable_resources(dev, bars)) { 6027506dc79SFrederick Lawler pci_err(dev, "SR-IOV: IOV BARS not allocated\n"); 603bbef98abSRam Pai return -ENOMEM; 604bbef98abSRam Pai } 605bbef98abSRam Pai 606dd7cc44dSYu Zhao if (iov->link != dev->devfn) { 607dd7cc44dSYu Zhao pdev = pci_get_slot(dev->bus, iov->link); 608dd7cc44dSYu Zhao if (!pdev) 609dd7cc44dSYu Zhao return -ENODEV; 610dd7cc44dSYu Zhao 611dc087f2fSJiang Liu if (!pdev->is_physfn) { 612dd7cc44dSYu Zhao pci_dev_put(pdev); 613652d1100SStefan Assmann return -ENOSYS; 614dc087f2fSJiang Liu } 615dd7cc44dSYu Zhao 616dd7cc44dSYu Zhao rc = sysfs_create_link(&dev->dev.kobj, 617dd7cc44dSYu Zhao &pdev->dev.kobj, "dep_link"); 618dc087f2fSJiang Liu pci_dev_put(pdev); 619dd7cc44dSYu Zhao if (rc) 620dd7cc44dSYu Zhao return rc; 621dd7cc44dSYu Zhao } 622dd7cc44dSYu Zhao 6236b136724SBjorn Helgaas iov->initial_VFs = initial; 624dd7cc44dSYu Zhao if (nr_virtfn < initial) 625dd7cc44dSYu Zhao initial = nr_virtfn; 626dd7cc44dSYu Zhao 627c23b6135SAlexander Duyck rc = pcibios_sriov_enable(dev, initial); 628c23b6135SAlexander Duyck if (rc) { 6297506dc79SFrederick Lawler pci_err(dev, "failure %d from pcibios_sriov_enable()\n", rc); 630c23b6135SAlexander Duyck goto err_pcibios; 631995df527SWei Yang } 632995df527SWei Yang 633f40ec3c7SGavin Shan pci_iov_set_numvfs(dev, nr_virtfn); 634f40ec3c7SGavin Shan iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; 635f40ec3c7SGavin Shan pci_cfg_access_lock(dev); 636f40ec3c7SGavin Shan pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 637f40ec3c7SGavin Shan msleep(100); 638f40ec3c7SGavin Shan pci_cfg_access_unlock(dev); 639f40ec3c7SGavin Shan 64018f9e9d1SSebastian Ott rc = sriov_add_vfs(dev, initial); 641dd7cc44dSYu Zhao if (rc) 64218f9e9d1SSebastian Ott goto err_pcibios; 643dd7cc44dSYu Zhao 644dd7cc44dSYu Zhao kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); 6456b136724SBjorn Helgaas iov->num_VFs = nr_virtfn; 646dd7cc44dSYu Zhao 647dd7cc44dSYu Zhao return 0; 648dd7cc44dSYu Zhao 649c23b6135SAlexander Duyck err_pcibios: 650dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 651fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 652dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 653dd7cc44dSYu Zhao ssleep(1); 654fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 655dd7cc44dSYu Zhao 6560fc690a7SGavin Shan pcibios_sriov_disable(dev); 6570fc690a7SGavin Shan 658dd7cc44dSYu Zhao if (iov->link != dev->devfn) 659dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 660dd7cc44dSYu Zhao 661b3908644SAlexander Duyck pci_iov_set_numvfs(dev, 0); 662dd7cc44dSYu Zhao return rc; 663dd7cc44dSYu Zhao } 664dd7cc44dSYu Zhao 66518f9e9d1SSebastian Ott static void sriov_del_vfs(struct pci_dev *dev) 66618f9e9d1SSebastian Ott { 66718f9e9d1SSebastian Ott struct pci_sriov *iov = dev->sriov; 66818f9e9d1SSebastian Ott int i; 66918f9e9d1SSebastian Ott 67018f9e9d1SSebastian Ott for (i = 0; i < iov->num_VFs; i++) 67118f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 67218f9e9d1SSebastian Ott } 67318f9e9d1SSebastian Ott 674dd7cc44dSYu Zhao static void sriov_disable(struct pci_dev *dev) 675dd7cc44dSYu Zhao { 676dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 677dd7cc44dSYu Zhao 6786b136724SBjorn Helgaas if (!iov->num_VFs) 679dd7cc44dSYu Zhao return; 680dd7cc44dSYu Zhao 68118f9e9d1SSebastian Ott sriov_del_vfs(dev); 682dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 683fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 684dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 685dd7cc44dSYu Zhao ssleep(1); 686fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 687dd7cc44dSYu Zhao 6880fc690a7SGavin Shan pcibios_sriov_disable(dev); 6890fc690a7SGavin Shan 690dd7cc44dSYu Zhao if (iov->link != dev->devfn) 691dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 692dd7cc44dSYu Zhao 6936b136724SBjorn Helgaas iov->num_VFs = 0; 694f59dca27SWei Yang pci_iov_set_numvfs(dev, 0); 695dd7cc44dSYu Zhao } 696dd7cc44dSYu Zhao 697d1b054daSYu Zhao static int sriov_init(struct pci_dev *dev, int pos) 698d1b054daSYu Zhao { 6990e6c9122SWei Yang int i, bar64; 700d1b054daSYu Zhao int rc; 701d1b054daSYu Zhao int nres; 702d1b054daSYu Zhao u32 pgsz; 703ea9a8854SAlexander Duyck u16 ctrl, total; 704d1b054daSYu Zhao struct pci_sriov *iov; 705d1b054daSYu Zhao struct resource *res; 706d1b054daSYu Zhao struct pci_dev *pdev; 707d1b054daSYu Zhao 708d1b054daSYu Zhao pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl); 709d1b054daSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) { 710d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0); 711d1b054daSYu Zhao ssleep(1); 712d1b054daSYu Zhao } 713d1b054daSYu Zhao 714d1b054daSYu Zhao ctrl = 0; 715d1b054daSYu Zhao list_for_each_entry(pdev, &dev->bus->devices, bus_list) 716d1b054daSYu Zhao if (pdev->is_physfn) 717d1b054daSYu Zhao goto found; 718d1b054daSYu Zhao 719d1b054daSYu Zhao pdev = NULL; 720d1b054daSYu Zhao if (pci_ari_enabled(dev->bus)) 721d1b054daSYu Zhao ctrl |= PCI_SRIOV_CTRL_ARI; 722d1b054daSYu Zhao 723d1b054daSYu Zhao found: 724d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); 725d1b054daSYu Zhao 726ff45f9ddSBen Shelton pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); 727ff45f9ddSBen Shelton if (!total) 728ff45f9ddSBen Shelton return 0; 729d1b054daSYu Zhao 730d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz); 731d1b054daSYu Zhao i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0; 732d1b054daSYu Zhao pgsz &= ~((1 << i) - 1); 733d1b054daSYu Zhao if (!pgsz) 734d1b054daSYu Zhao return -EIO; 735d1b054daSYu Zhao 736d1b054daSYu Zhao pgsz &= ~(pgsz - 1); 7378161fe91SVaidyanathan Srinivasan pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); 738d1b054daSYu Zhao 7390e6c9122SWei Yang iov = kzalloc(sizeof(*iov), GFP_KERNEL); 7400e6c9122SWei Yang if (!iov) 7410e6c9122SWei Yang return -ENOMEM; 7420e6c9122SWei Yang 743d1b054daSYu Zhao nres = 0; 744d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 745c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 74611183991SDavid Daney /* 74711183991SDavid Daney * If it is already FIXED, don't change it, something 74811183991SDavid Daney * (perhaps EA or header fixups) wants it this way. 74911183991SDavid Daney */ 75011183991SDavid Daney if (res->flags & IORESOURCE_PCI_FIXED) 75111183991SDavid Daney bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0; 75211183991SDavid Daney else 7530e6c9122SWei Yang bar64 = __pci_read_base(dev, pci_bar_unknown, res, 754d1b054daSYu Zhao pos + PCI_SRIOV_BAR + i * 4); 755d1b054daSYu Zhao if (!res->flags) 756d1b054daSYu Zhao continue; 757d1b054daSYu Zhao if (resource_size(res) & (PAGE_SIZE - 1)) { 758d1b054daSYu Zhao rc = -EIO; 759d1b054daSYu Zhao goto failed; 760d1b054daSYu Zhao } 7610e6c9122SWei Yang iov->barsz[i] = resource_size(res); 762d1b054daSYu Zhao res->end = res->start + resource_size(res) * total - 1; 7637506dc79SFrederick Lawler pci_info(dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n", 764e88ae01dSWei Yang i, res, i, total); 7650e6c9122SWei Yang i += bar64; 766d1b054daSYu Zhao nres++; 767d1b054daSYu Zhao } 768d1b054daSYu Zhao 769d1b054daSYu Zhao iov->pos = pos; 770d1b054daSYu Zhao iov->nres = nres; 771d1b054daSYu Zhao iov->ctrl = ctrl; 7726b136724SBjorn Helgaas iov->total_VFs = total; 7738d85a7a4SJakub Kicinski iov->driver_max_VFs = total; 7743142d832SFilippo Sironi pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device); 775d1b054daSYu Zhao iov->pgsz = pgsz; 776d1b054daSYu Zhao iov->self = dev; 7770e7df224SBodong Wang iov->drivers_autoprobe = true; 778d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); 779d1b054daSYu Zhao pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 78062f87c0eSYijing Wang if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) 7814d135dbeSYu Zhao iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link); 782d1b054daSYu Zhao 783d1b054daSYu Zhao if (pdev) 784d1b054daSYu Zhao iov->dev = pci_dev_get(pdev); 785e277d2fcSYu Zhao else 786d1b054daSYu Zhao iov->dev = dev; 787e277d2fcSYu Zhao 788d1b054daSYu Zhao dev->sriov = iov; 789d1b054daSYu Zhao dev->is_physfn = 1; 790ea9a8854SAlexander Duyck rc = compute_max_vf_buses(dev); 791ea9a8854SAlexander Duyck if (rc) 792ea9a8854SAlexander Duyck goto fail_max_buses; 793d1b054daSYu Zhao 794d1b054daSYu Zhao return 0; 795d1b054daSYu Zhao 796ea9a8854SAlexander Duyck fail_max_buses: 797ea9a8854SAlexander Duyck dev->sriov = NULL; 798ea9a8854SAlexander Duyck dev->is_physfn = 0; 799d1b054daSYu Zhao failed: 800d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 801c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 802d1b054daSYu Zhao res->flags = 0; 803d1b054daSYu Zhao } 804d1b054daSYu Zhao 8050e6c9122SWei Yang kfree(iov); 806d1b054daSYu Zhao return rc; 807d1b054daSYu Zhao } 808d1b054daSYu Zhao 809d1b054daSYu Zhao static void sriov_release(struct pci_dev *dev) 810d1b054daSYu Zhao { 8116b136724SBjorn Helgaas BUG_ON(dev->sriov->num_VFs); 812dd7cc44dSYu Zhao 813e277d2fcSYu Zhao if (dev != dev->sriov->dev) 814d1b054daSYu Zhao pci_dev_put(dev->sriov->dev); 815d1b054daSYu Zhao 816d1b054daSYu Zhao kfree(dev->sriov); 817d1b054daSYu Zhao dev->sriov = NULL; 818d1b054daSYu Zhao } 819d1b054daSYu Zhao 8208c5cdb6aSYu Zhao static void sriov_restore_state(struct pci_dev *dev) 8218c5cdb6aSYu Zhao { 8228c5cdb6aSYu Zhao int i; 8238c5cdb6aSYu Zhao u16 ctrl; 8248c5cdb6aSYu Zhao struct pci_sriov *iov = dev->sriov; 8258c5cdb6aSYu Zhao 8268c5cdb6aSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl); 8278c5cdb6aSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) 8288c5cdb6aSYu Zhao return; 8298c5cdb6aSYu Zhao 830ff26449eSTony Nguyen /* 831ff26449eSTony Nguyen * Restore PCI_SRIOV_CTRL_ARI before pci_iov_set_numvfs() because 832ff26449eSTony Nguyen * it reads offset & stride, which depend on PCI_SRIOV_CTRL_ARI. 833ff26449eSTony Nguyen */ 834ff26449eSTony Nguyen ctrl &= ~PCI_SRIOV_CTRL_ARI; 835ff26449eSTony Nguyen ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI; 836ff26449eSTony Nguyen pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl); 837ff26449eSTony Nguyen 83839098edbSDenis Efremov for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) 83939098edbSDenis Efremov pci_update_resource(dev, i + PCI_IOV_RESOURCES); 8408c5cdb6aSYu Zhao 8418c5cdb6aSYu Zhao pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); 842f59dca27SWei Yang pci_iov_set_numvfs(dev, iov->num_VFs); 8438c5cdb6aSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 8448c5cdb6aSYu Zhao if (iov->ctrl & PCI_SRIOV_CTRL_VFE) 8458c5cdb6aSYu Zhao msleep(100); 8468c5cdb6aSYu Zhao } 8478c5cdb6aSYu Zhao 848d1b054daSYu Zhao /** 849d1b054daSYu Zhao * pci_iov_init - initialize the IOV capability 850d1b054daSYu Zhao * @dev: the PCI device 851d1b054daSYu Zhao * 852d1b054daSYu Zhao * Returns 0 on success, or negative on failure. 853d1b054daSYu Zhao */ 854d1b054daSYu Zhao int pci_iov_init(struct pci_dev *dev) 855d1b054daSYu Zhao { 856d1b054daSYu Zhao int pos; 857d1b054daSYu Zhao 8585f4d91a1SKenji Kaneshige if (!pci_is_pcie(dev)) 859d1b054daSYu Zhao return -ENODEV; 860d1b054daSYu Zhao 861d1b054daSYu Zhao pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); 862d1b054daSYu Zhao if (pos) 863d1b054daSYu Zhao return sriov_init(dev, pos); 864d1b054daSYu Zhao 865d1b054daSYu Zhao return -ENODEV; 866d1b054daSYu Zhao } 867d1b054daSYu Zhao 868d1b054daSYu Zhao /** 869d1b054daSYu Zhao * pci_iov_release - release resources used by the IOV capability 870d1b054daSYu Zhao * @dev: the PCI device 871d1b054daSYu Zhao */ 872d1b054daSYu Zhao void pci_iov_release(struct pci_dev *dev) 873d1b054daSYu Zhao { 874d1b054daSYu Zhao if (dev->is_physfn) 875d1b054daSYu Zhao sriov_release(dev); 876d1b054daSYu Zhao } 877d1b054daSYu Zhao 878d1b054daSYu Zhao /** 87938972375SJakub Kicinski * pci_iov_remove - clean up SR-IOV state after PF driver is detached 88038972375SJakub Kicinski * @dev: the PCI device 88138972375SJakub Kicinski */ 88238972375SJakub Kicinski void pci_iov_remove(struct pci_dev *dev) 88338972375SJakub Kicinski { 88438972375SJakub Kicinski struct pci_sriov *iov = dev->sriov; 88538972375SJakub Kicinski 88638972375SJakub Kicinski if (!dev->is_physfn) 88738972375SJakub Kicinski return; 88838972375SJakub Kicinski 88938972375SJakub Kicinski iov->driver_max_VFs = iov->total_VFs; 89038972375SJakub Kicinski if (iov->num_VFs) 89138972375SJakub Kicinski pci_warn(dev, "driver left SR-IOV enabled after remove\n"); 89238972375SJakub Kicinski } 89338972375SJakub Kicinski 89438972375SJakub Kicinski /** 8956ffa2489SBjorn Helgaas * pci_iov_update_resource - update a VF BAR 8966ffa2489SBjorn Helgaas * @dev: the PCI device 8976ffa2489SBjorn Helgaas * @resno: the resource number 8986ffa2489SBjorn Helgaas * 8996ffa2489SBjorn Helgaas * Update a VF BAR in the SR-IOV capability of a PF. 9006ffa2489SBjorn Helgaas */ 9016ffa2489SBjorn Helgaas void pci_iov_update_resource(struct pci_dev *dev, int resno) 9026ffa2489SBjorn Helgaas { 9036ffa2489SBjorn Helgaas struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; 9046ffa2489SBjorn Helgaas struct resource *res = dev->resource + resno; 9056ffa2489SBjorn Helgaas int vf_bar = resno - PCI_IOV_RESOURCES; 9066ffa2489SBjorn Helgaas struct pci_bus_region region; 907546ba9f8SBjorn Helgaas u16 cmd; 9086ffa2489SBjorn Helgaas u32 new; 9096ffa2489SBjorn Helgaas int reg; 9106ffa2489SBjorn Helgaas 9116ffa2489SBjorn Helgaas /* 9126ffa2489SBjorn Helgaas * The generic pci_restore_bars() path calls this for all devices, 9136ffa2489SBjorn Helgaas * including VFs and non-SR-IOV devices. If this is not a PF, we 9146ffa2489SBjorn Helgaas * have nothing to do. 9156ffa2489SBjorn Helgaas */ 9166ffa2489SBjorn Helgaas if (!iov) 9176ffa2489SBjorn Helgaas return; 9186ffa2489SBjorn Helgaas 919546ba9f8SBjorn Helgaas pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); 920546ba9f8SBjorn Helgaas if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { 921546ba9f8SBjorn Helgaas dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", 922546ba9f8SBjorn Helgaas vf_bar, res); 923546ba9f8SBjorn Helgaas return; 924546ba9f8SBjorn Helgaas } 925546ba9f8SBjorn Helgaas 9266ffa2489SBjorn Helgaas /* 9276ffa2489SBjorn Helgaas * Ignore unimplemented BARs, unused resource slots for 64-bit 9286ffa2489SBjorn Helgaas * BARs, and non-movable resources, e.g., those described via 9296ffa2489SBjorn Helgaas * Enhanced Allocation. 9306ffa2489SBjorn Helgaas */ 9316ffa2489SBjorn Helgaas if (!res->flags) 9326ffa2489SBjorn Helgaas return; 9336ffa2489SBjorn Helgaas 9346ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_UNSET) 9356ffa2489SBjorn Helgaas return; 9366ffa2489SBjorn Helgaas 9376ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_PCI_FIXED) 9386ffa2489SBjorn Helgaas return; 9396ffa2489SBjorn Helgaas 9406ffa2489SBjorn Helgaas pcibios_resource_to_bus(dev->bus, ®ion, res); 9416ffa2489SBjorn Helgaas new = region.start; 9426ffa2489SBjorn Helgaas new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; 9436ffa2489SBjorn Helgaas 9446ffa2489SBjorn Helgaas reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar; 9456ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg, new); 9466ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_MEM_64) { 9476ffa2489SBjorn Helgaas new = region.start >> 16 >> 16; 9486ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg + 4, new); 9496ffa2489SBjorn Helgaas } 9506ffa2489SBjorn Helgaas } 9516ffa2489SBjorn Helgaas 952978d2d68SWei Yang resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev, 953978d2d68SWei Yang int resno) 954978d2d68SWei Yang { 955978d2d68SWei Yang return pci_iov_resource_size(dev, resno); 956978d2d68SWei Yang } 957978d2d68SWei Yang 9588c5cdb6aSYu Zhao /** 9596faf17f6SChris Wright * pci_sriov_resource_alignment - get resource alignment for VF BAR 9606faf17f6SChris Wright * @dev: the PCI device 9616faf17f6SChris Wright * @resno: the resource number 9626faf17f6SChris Wright * 9636faf17f6SChris Wright * Returns the alignment of the VF BAR found in the SR-IOV capability. 9646faf17f6SChris Wright * This is not the same as the resource size which is defined as 9656faf17f6SChris Wright * the VF BAR size multiplied by the number of VFs. The alignment 9666faf17f6SChris Wright * is just the VF BAR size. 9676faf17f6SChris Wright */ 9680e52247aSCam Macdonell resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) 9696faf17f6SChris Wright { 970978d2d68SWei Yang return pcibios_iov_resource_alignment(dev, resno); 9716faf17f6SChris Wright } 9726faf17f6SChris Wright 9736faf17f6SChris Wright /** 9748c5cdb6aSYu Zhao * pci_restore_iov_state - restore the state of the IOV capability 9758c5cdb6aSYu Zhao * @dev: the PCI device 9768c5cdb6aSYu Zhao */ 9778c5cdb6aSYu Zhao void pci_restore_iov_state(struct pci_dev *dev) 9788c5cdb6aSYu Zhao { 9798c5cdb6aSYu Zhao if (dev->is_physfn) 9808c5cdb6aSYu Zhao sriov_restore_state(dev); 9818c5cdb6aSYu Zhao } 982a28724b0SYu Zhao 983a28724b0SYu Zhao /** 984608c0d88SBryant G. Ly * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs 985608c0d88SBryant G. Ly * @dev: the PCI device 986608c0d88SBryant G. Ly * @auto_probe: set VF drivers auto probe flag 987608c0d88SBryant G. Ly */ 988608c0d88SBryant G. Ly void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe) 989608c0d88SBryant G. Ly { 990608c0d88SBryant G. Ly if (dev->is_physfn) 991608c0d88SBryant G. Ly dev->sriov->drivers_autoprobe = auto_probe; 992608c0d88SBryant G. Ly } 993608c0d88SBryant G. Ly 994608c0d88SBryant G. Ly /** 995a28724b0SYu Zhao * pci_iov_bus_range - find bus range used by Virtual Function 996a28724b0SYu Zhao * @bus: the PCI bus 997a28724b0SYu Zhao * 998a28724b0SYu Zhao * Returns max number of buses (exclude current one) used by Virtual 999a28724b0SYu Zhao * Functions. 1000a28724b0SYu Zhao */ 1001a28724b0SYu Zhao int pci_iov_bus_range(struct pci_bus *bus) 1002a28724b0SYu Zhao { 1003a28724b0SYu Zhao int max = 0; 1004a28724b0SYu Zhao struct pci_dev *dev; 1005a28724b0SYu Zhao 1006a28724b0SYu Zhao list_for_each_entry(dev, &bus->devices, bus_list) { 1007a28724b0SYu Zhao if (!dev->is_physfn) 1008a28724b0SYu Zhao continue; 10094449f079SWei Yang if (dev->sriov->max_VF_buses > max) 10104449f079SWei Yang max = dev->sriov->max_VF_buses; 1011a28724b0SYu Zhao } 1012a28724b0SYu Zhao 1013a28724b0SYu Zhao return max ? max - bus->number : 0; 1014a28724b0SYu Zhao } 1015dd7cc44dSYu Zhao 1016dd7cc44dSYu Zhao /** 1017dd7cc44dSYu Zhao * pci_enable_sriov - enable the SR-IOV capability 1018dd7cc44dSYu Zhao * @dev: the PCI device 101952a8873bSRandy Dunlap * @nr_virtfn: number of virtual functions to enable 1020dd7cc44dSYu Zhao * 1021dd7cc44dSYu Zhao * Returns 0 on success, or negative on failure. 1022dd7cc44dSYu Zhao */ 1023dd7cc44dSYu Zhao int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) 1024dd7cc44dSYu Zhao { 1025dd7cc44dSYu Zhao might_sleep(); 1026dd7cc44dSYu Zhao 1027dd7cc44dSYu Zhao if (!dev->is_physfn) 1028652d1100SStefan Assmann return -ENOSYS; 1029dd7cc44dSYu Zhao 1030dd7cc44dSYu Zhao return sriov_enable(dev, nr_virtfn); 1031dd7cc44dSYu Zhao } 1032dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_enable_sriov); 1033dd7cc44dSYu Zhao 1034dd7cc44dSYu Zhao /** 1035dd7cc44dSYu Zhao * pci_disable_sriov - disable the SR-IOV capability 1036dd7cc44dSYu Zhao * @dev: the PCI device 1037dd7cc44dSYu Zhao */ 1038dd7cc44dSYu Zhao void pci_disable_sriov(struct pci_dev *dev) 1039dd7cc44dSYu Zhao { 1040dd7cc44dSYu Zhao might_sleep(); 1041dd7cc44dSYu Zhao 1042dd7cc44dSYu Zhao if (!dev->is_physfn) 1043dd7cc44dSYu Zhao return; 1044dd7cc44dSYu Zhao 1045dd7cc44dSYu Zhao sriov_disable(dev); 1046dd7cc44dSYu Zhao } 1047dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_disable_sriov); 104874bb1bccSYu Zhao 104974bb1bccSYu Zhao /** 1050fb8a0d9dSWilliams, Mitch A * pci_num_vf - return number of VFs associated with a PF device_release_driver 1051fb8a0d9dSWilliams, Mitch A * @dev: the PCI device 1052fb8a0d9dSWilliams, Mitch A * 1053fb8a0d9dSWilliams, Mitch A * Returns number of VFs, or 0 if SR-IOV is not enabled. 1054fb8a0d9dSWilliams, Mitch A */ 1055fb8a0d9dSWilliams, Mitch A int pci_num_vf(struct pci_dev *dev) 1056fb8a0d9dSWilliams, Mitch A { 10571452cd76SBjorn Helgaas if (!dev->is_physfn) 1058fb8a0d9dSWilliams, Mitch A return 0; 10591452cd76SBjorn Helgaas 10606b136724SBjorn Helgaas return dev->sriov->num_VFs; 1061fb8a0d9dSWilliams, Mitch A } 1062fb8a0d9dSWilliams, Mitch A EXPORT_SYMBOL_GPL(pci_num_vf); 1063bff73156SDonald Dutile 1064bff73156SDonald Dutile /** 10655a8eb242SAlexander Duyck * pci_vfs_assigned - returns number of VFs are assigned to a guest 10665a8eb242SAlexander Duyck * @dev: the PCI device 10675a8eb242SAlexander Duyck * 10685a8eb242SAlexander Duyck * Returns number of VFs belonging to this device that are assigned to a guest. 1069652d1100SStefan Assmann * If device is not a physical function returns 0. 10705a8eb242SAlexander Duyck */ 10715a8eb242SAlexander Duyck int pci_vfs_assigned(struct pci_dev *dev) 10725a8eb242SAlexander Duyck { 10735a8eb242SAlexander Duyck struct pci_dev *vfdev; 10745a8eb242SAlexander Duyck unsigned int vfs_assigned = 0; 10755a8eb242SAlexander Duyck unsigned short dev_id; 10765a8eb242SAlexander Duyck 10775a8eb242SAlexander Duyck /* only search if we are a PF */ 10785a8eb242SAlexander Duyck if (!dev->is_physfn) 10795a8eb242SAlexander Duyck return 0; 10805a8eb242SAlexander Duyck 10815a8eb242SAlexander Duyck /* 10825a8eb242SAlexander Duyck * determine the device ID for the VFs, the vendor ID will be the 10835a8eb242SAlexander Duyck * same as the PF so there is no need to check for that one 10845a8eb242SAlexander Duyck */ 10853142d832SFilippo Sironi dev_id = dev->sriov->vf_device; 10865a8eb242SAlexander Duyck 10875a8eb242SAlexander Duyck /* loop through all the VFs to see if we own any that are assigned */ 10885a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, NULL); 10895a8eb242SAlexander Duyck while (vfdev) { 10905a8eb242SAlexander Duyck /* 10915a8eb242SAlexander Duyck * It is considered assigned if it is a virtual function with 10925a8eb242SAlexander Duyck * our dev as the physical function and the assigned bit is set 10935a8eb242SAlexander Duyck */ 10945a8eb242SAlexander Duyck if (vfdev->is_virtfn && (vfdev->physfn == dev) && 1095be63497cSEthan Zhao pci_is_dev_assigned(vfdev)) 10965a8eb242SAlexander Duyck vfs_assigned++; 10975a8eb242SAlexander Duyck 10985a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, vfdev); 10995a8eb242SAlexander Duyck } 11005a8eb242SAlexander Duyck 11015a8eb242SAlexander Duyck return vfs_assigned; 11025a8eb242SAlexander Duyck } 11035a8eb242SAlexander Duyck EXPORT_SYMBOL_GPL(pci_vfs_assigned); 11045a8eb242SAlexander Duyck 11055a8eb242SAlexander Duyck /** 1106bff73156SDonald Dutile * pci_sriov_set_totalvfs -- reduce the TotalVFs available 1107bff73156SDonald Dutile * @dev: the PCI PF device 11082094f167SRandy Dunlap * @numvfs: number that should be used for TotalVFs supported 1109bff73156SDonald Dutile * 1110bff73156SDonald Dutile * Should be called from PF driver's probe routine with 1111bff73156SDonald Dutile * device's mutex held. 1112bff73156SDonald Dutile * 1113bff73156SDonald Dutile * Returns 0 if PF is an SRIOV-capable device and 1114652d1100SStefan Assmann * value of numvfs valid. If not a PF return -ENOSYS; 1115652d1100SStefan Assmann * if numvfs is invalid return -EINVAL; 1116bff73156SDonald Dutile * if VFs already enabled, return -EBUSY. 1117bff73156SDonald Dutile */ 1118bff73156SDonald Dutile int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) 1119bff73156SDonald Dutile { 1120652d1100SStefan Assmann if (!dev->is_physfn) 1121652d1100SStefan Assmann return -ENOSYS; 112251259d00SBjorn Helgaas 1123652d1100SStefan Assmann if (numvfs > dev->sriov->total_VFs) 1124bff73156SDonald Dutile return -EINVAL; 1125bff73156SDonald Dutile 1126bff73156SDonald Dutile /* Shouldn't change if VFs already enabled */ 1127bff73156SDonald Dutile if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) 1128bff73156SDonald Dutile return -EBUSY; 1129bff73156SDonald Dutile 113051259d00SBjorn Helgaas dev->sriov->driver_max_VFs = numvfs; 1131bff73156SDonald Dutile return 0; 1132bff73156SDonald Dutile } 1133bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); 1134bff73156SDonald Dutile 1135bff73156SDonald Dutile /** 1136ddc191f5SJonghwan Choi * pci_sriov_get_totalvfs -- get total VFs supported on this device 1137bff73156SDonald Dutile * @dev: the PCI PF device 1138bff73156SDonald Dutile * 1139bff73156SDonald Dutile * For a PCIe device with SRIOV support, return the PCIe 11406b136724SBjorn Helgaas * SRIOV capability value of TotalVFs or the value of driver_max_VFs 1141652d1100SStefan Assmann * if the driver reduced it. Otherwise 0. 1142bff73156SDonald Dutile */ 1143bff73156SDonald Dutile int pci_sriov_get_totalvfs(struct pci_dev *dev) 1144bff73156SDonald Dutile { 11451452cd76SBjorn Helgaas if (!dev->is_physfn) 1146652d1100SStefan Assmann return 0; 1147bff73156SDonald Dutile 11486b136724SBjorn Helgaas return dev->sriov->driver_max_VFs; 1149bff73156SDonald Dutile } 1150bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); 11518effc395SAlexander Duyck 11528effc395SAlexander Duyck /** 11538effc395SAlexander Duyck * pci_sriov_configure_simple - helper to configure SR-IOV 11548effc395SAlexander Duyck * @dev: the PCI device 11558effc395SAlexander Duyck * @nr_virtfn: number of virtual functions to enable, 0 to disable 11568effc395SAlexander Duyck * 11578effc395SAlexander Duyck * Enable or disable SR-IOV for devices that don't require any PF setup 11588effc395SAlexander Duyck * before enabling SR-IOV. Return value is negative on error, or number of 11598effc395SAlexander Duyck * VFs allocated on success. 11608effc395SAlexander Duyck */ 11618effc395SAlexander Duyck int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn) 11628effc395SAlexander Duyck { 11638effc395SAlexander Duyck int rc; 11648effc395SAlexander Duyck 11658effc395SAlexander Duyck might_sleep(); 11668effc395SAlexander Duyck 11678effc395SAlexander Duyck if (!dev->is_physfn) 11688effc395SAlexander Duyck return -ENODEV; 11698effc395SAlexander Duyck 11708effc395SAlexander Duyck if (pci_vfs_assigned(dev)) { 11718effc395SAlexander Duyck pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n"); 11728effc395SAlexander Duyck return -EPERM; 11738effc395SAlexander Duyck } 11748effc395SAlexander Duyck 11758effc395SAlexander Duyck if (nr_virtfn == 0) { 11768effc395SAlexander Duyck sriov_disable(dev); 11778effc395SAlexander Duyck return 0; 11788effc395SAlexander Duyck } 11798effc395SAlexander Duyck 11808effc395SAlexander Duyck rc = sriov_enable(dev, nr_virtfn); 11818effc395SAlexander Duyck if (rc < 0) 11828effc395SAlexander Duyck return rc; 11838effc395SAlexander Duyck 11848effc395SAlexander Duyck return nr_virtfn; 11858effc395SAlexander Duyck } 11868effc395SAlexander Duyck EXPORT_SYMBOL_GPL(pci_sriov_configure_simple); 1187