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 } 34a28724b0SYu Zhao 35f59dca27SWei Yang /* 36f59dca27SWei Yang * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may 37f59dca27SWei Yang * change when NumVFs changes. 38f59dca27SWei Yang * 39f59dca27SWei Yang * Update iov->offset and iov->stride when NumVFs is written. 40f59dca27SWei Yang */ 41f59dca27SWei Yang static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn) 42f59dca27SWei Yang { 43f59dca27SWei Yang struct pci_sriov *iov = dev->sriov; 44f59dca27SWei Yang 45f59dca27SWei Yang pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); 46f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &iov->offset); 47f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride); 48f59dca27SWei Yang } 49f59dca27SWei Yang 504449f079SWei Yang /* 514449f079SWei Yang * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride 524449f079SWei Yang * determine how many additional bus numbers will be consumed by VFs. 534449f079SWei Yang * 54ea9a8854SAlexander Duyck * Iterate over all valid NumVFs, validate offset and stride, and calculate 55ea9a8854SAlexander Duyck * the maximum number of bus numbers that could ever be required. 564449f079SWei Yang */ 57ea9a8854SAlexander Duyck static int compute_max_vf_buses(struct pci_dev *dev) 584449f079SWei Yang { 594449f079SWei Yang struct pci_sriov *iov = dev->sriov; 60ea9a8854SAlexander Duyck int nr_virtfn, busnr, rc = 0; 614449f079SWei Yang 62ea9a8854SAlexander Duyck for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) { 634449f079SWei Yang pci_iov_set_numvfs(dev, nr_virtfn); 64ea9a8854SAlexander Duyck if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) { 65ea9a8854SAlexander Duyck rc = -EIO; 66ea9a8854SAlexander Duyck goto out; 674449f079SWei Yang } 684449f079SWei Yang 69ea9a8854SAlexander Duyck busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 70ea9a8854SAlexander Duyck if (busnr > iov->max_VF_buses) 71ea9a8854SAlexander Duyck iov->max_VF_buses = busnr; 72ea9a8854SAlexander Duyck } 73ea9a8854SAlexander Duyck 74ea9a8854SAlexander Duyck out: 75ea9a8854SAlexander Duyck pci_iov_set_numvfs(dev, 0); 76ea9a8854SAlexander Duyck return rc; 774449f079SWei Yang } 784449f079SWei Yang 79dd7cc44dSYu Zhao static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) 80dd7cc44dSYu Zhao { 81dd7cc44dSYu Zhao struct pci_bus *child; 82dd7cc44dSYu Zhao 83dd7cc44dSYu Zhao if (bus->number == busnr) 84dd7cc44dSYu Zhao return bus; 85dd7cc44dSYu Zhao 86dd7cc44dSYu Zhao child = pci_find_bus(pci_domain_nr(bus), busnr); 87dd7cc44dSYu Zhao if (child) 88dd7cc44dSYu Zhao return child; 89dd7cc44dSYu Zhao 90dd7cc44dSYu Zhao child = pci_add_new_bus(bus, NULL, busnr); 91dd7cc44dSYu Zhao if (!child) 92dd7cc44dSYu Zhao return NULL; 93dd7cc44dSYu Zhao 94b7eac055SYinghai Lu pci_bus_insert_busn_res(child, busnr, busnr); 95dd7cc44dSYu Zhao 96dd7cc44dSYu Zhao return child; 97dd7cc44dSYu Zhao } 98dd7cc44dSYu Zhao 99dc087f2fSJiang Liu static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus) 100dd7cc44dSYu Zhao { 101dc087f2fSJiang Liu if (physbus != virtbus && list_empty(&virtbus->devices)) 102dc087f2fSJiang Liu pci_remove_bus(virtbus); 103dd7cc44dSYu Zhao } 104dd7cc44dSYu Zhao 1050e6c9122SWei Yang resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) 1060e6c9122SWei Yang { 1070e6c9122SWei Yang if (!dev->is_physfn) 1080e6c9122SWei Yang return 0; 1090e6c9122SWei Yang 1100e6c9122SWei Yang return dev->sriov->barsz[resno - PCI_IOV_RESOURCES]; 1110e6c9122SWei Yang } 1120e6c9122SWei Yang 113cf0921beSKarimAllah Ahmed static void pci_read_vf_config_common(struct pci_dev *virtfn) 114cf0921beSKarimAllah Ahmed { 115cf0921beSKarimAllah Ahmed struct pci_dev *physfn = virtfn->physfn; 116cf0921beSKarimAllah Ahmed 117cf0921beSKarimAllah Ahmed /* 118cf0921beSKarimAllah Ahmed * Some config registers are the same across all associated VFs. 119cf0921beSKarimAllah Ahmed * Read them once from VF0 so we can skip reading them from the 120cf0921beSKarimAllah Ahmed * other VFs. 121cf0921beSKarimAllah Ahmed * 122cf0921beSKarimAllah Ahmed * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to 123cf0921beSKarimAllah Ahmed * have the same Revision ID and Subsystem ID, but we assume they 124cf0921beSKarimAllah Ahmed * do. 125cf0921beSKarimAllah Ahmed */ 126cf0921beSKarimAllah Ahmed pci_read_config_dword(virtfn, PCI_CLASS_REVISION, 127cf0921beSKarimAllah Ahmed &physfn->sriov->class); 128cf0921beSKarimAllah Ahmed pci_read_config_byte(virtfn, PCI_HEADER_TYPE, 129cf0921beSKarimAllah Ahmed &physfn->sriov->hdr_type); 130cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID, 131cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_vendor); 132cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID, 133cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_device); 134cf0921beSKarimAllah Ahmed } 135cf0921beSKarimAllah Ahmed 136a1ceea67SNiklas Schnelle int pci_iov_sysfs_link(struct pci_dev *dev, 137a1ceea67SNiklas Schnelle struct pci_dev *virtfn, int id) 138a1ceea67SNiklas Schnelle { 139a1ceea67SNiklas Schnelle char buf[VIRTFN_ID_LEN]; 140a1ceea67SNiklas Schnelle int rc; 141a1ceea67SNiklas Schnelle 142a1ceea67SNiklas Schnelle sprintf(buf, "virtfn%u", id); 143a1ceea67SNiklas Schnelle rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); 144a1ceea67SNiklas Schnelle if (rc) 145a1ceea67SNiklas Schnelle goto failed; 146a1ceea67SNiklas Schnelle rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn"); 147a1ceea67SNiklas Schnelle if (rc) 148a1ceea67SNiklas Schnelle goto failed1; 149a1ceea67SNiklas Schnelle 150a1ceea67SNiklas Schnelle kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); 151a1ceea67SNiklas Schnelle 152a1ceea67SNiklas Schnelle return 0; 153a1ceea67SNiklas Schnelle 154a1ceea67SNiklas Schnelle failed1: 155a1ceea67SNiklas Schnelle sysfs_remove_link(&dev->dev.kobj, buf); 156a1ceea67SNiklas Schnelle failed: 157a1ceea67SNiklas Schnelle return rc; 158a1ceea67SNiklas Schnelle } 159a1ceea67SNiklas Schnelle 160753f6124SJan H. Schönherr int pci_iov_add_virtfn(struct pci_dev *dev, int id) 161dd7cc44dSYu Zhao { 162dd7cc44dSYu Zhao int i; 163dc087f2fSJiang Liu int rc = -ENOMEM; 164dd7cc44dSYu Zhao u64 size; 165dd7cc44dSYu Zhao struct pci_dev *virtfn; 166dd7cc44dSYu Zhao struct resource *res; 167dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 1688b1fce04SGu Zheng struct pci_bus *bus; 169dd7cc44dSYu Zhao 170b07579c0SWei Yang bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id)); 171dc087f2fSJiang Liu if (!bus) 172dc087f2fSJiang Liu goto failed; 173dc087f2fSJiang Liu 174dc087f2fSJiang Liu virtfn = pci_alloc_dev(bus); 175dc087f2fSJiang Liu if (!virtfn) 176dc087f2fSJiang Liu goto failed0; 177dc087f2fSJiang Liu 178b07579c0SWei Yang virtfn->devfn = pci_iov_virtfn_devfn(dev, id); 179dd7cc44dSYu Zhao virtfn->vendor = dev->vendor; 1803142d832SFilippo Sironi virtfn->device = iov->vf_device; 181cf0921beSKarimAllah Ahmed virtfn->is_virtfn = 1; 182cf0921beSKarimAllah Ahmed virtfn->physfn = pci_dev_get(dev); 183*12856e7aSMatthew Rosato virtfn->no_command_memory = 1; 184cf0921beSKarimAllah Ahmed 185cf0921beSKarimAllah Ahmed if (id == 0) 186cf0921beSKarimAllah Ahmed pci_read_vf_config_common(virtfn); 187cf0921beSKarimAllah Ahmed 188156c5532SPo Liu rc = pci_setup_device(virtfn); 189156c5532SPo Liu if (rc) 190cf0921beSKarimAllah Ahmed goto failed1; 191156c5532SPo Liu 192dd7cc44dSYu Zhao virtfn->dev.parent = dev->dev.parent; 193aa931977SAlex Williamson virtfn->multifunction = 0; 194dd7cc44dSYu Zhao 195dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 196c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 197dd7cc44dSYu Zhao if (!res->parent) 198dd7cc44dSYu Zhao continue; 199dd7cc44dSYu Zhao virtfn->resource[i].name = pci_name(virtfn); 200dd7cc44dSYu Zhao virtfn->resource[i].flags = res->flags; 2010e6c9122SWei Yang size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES); 202dd7cc44dSYu Zhao virtfn->resource[i].start = res->start + size * id; 203dd7cc44dSYu Zhao virtfn->resource[i].end = virtfn->resource[i].start + size - 1; 204dd7cc44dSYu Zhao rc = request_resource(res, &virtfn->resource[i]); 205dd7cc44dSYu Zhao BUG_ON(rc); 206dd7cc44dSYu Zhao } 207dd7cc44dSYu Zhao 208dd7cc44dSYu Zhao pci_device_add(virtfn, virtfn->bus); 209a1ceea67SNiklas Schnelle rc = pci_iov_sysfs_link(dev, virtfn, id); 210dd7cc44dSYu Zhao if (rc) 2118c386cc8SNavid Emamdoost goto failed1; 212dd7cc44dSYu Zhao 21327d61629SStuart Hayes pci_bus_add_device(virtfn); 21427d61629SStuart Hayes 215dd7cc44dSYu Zhao return 0; 216dd7cc44dSYu Zhao 217dd7cc44dSYu Zhao failed1: 2188c386cc8SNavid Emamdoost pci_stop_and_remove_bus_device(virtfn); 219dd7cc44dSYu Zhao pci_dev_put(dev); 220dc087f2fSJiang Liu failed0: 221dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, bus); 222dc087f2fSJiang Liu failed: 223dd7cc44dSYu Zhao 224dd7cc44dSYu Zhao return rc; 225dd7cc44dSYu Zhao } 226dd7cc44dSYu Zhao 227753f6124SJan H. Schönherr void pci_iov_remove_virtfn(struct pci_dev *dev, int id) 228dd7cc44dSYu Zhao { 229dd7cc44dSYu Zhao char buf[VIRTFN_ID_LEN]; 230dd7cc44dSYu Zhao struct pci_dev *virtfn; 231dd7cc44dSYu Zhao 232dc087f2fSJiang Liu virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), 233b07579c0SWei Yang pci_iov_virtfn_bus(dev, id), 234b07579c0SWei Yang pci_iov_virtfn_devfn(dev, id)); 235dd7cc44dSYu Zhao if (!virtfn) 236dd7cc44dSYu Zhao return; 237dd7cc44dSYu Zhao 238dd7cc44dSYu Zhao sprintf(buf, "virtfn%u", id); 239dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, buf); 24009cedbefSYinghai Lu /* 24109cedbefSYinghai Lu * pci_stop_dev() could have been called for this virtfn already, 24209cedbefSYinghai Lu * so the directory for the virtfn may have been removed before. 24309cedbefSYinghai Lu * Double check to avoid spurious sysfs warnings. 24409cedbefSYinghai Lu */ 24509cedbefSYinghai Lu if (virtfn->dev.kobj.sd) 246dd7cc44dSYu Zhao sysfs_remove_link(&virtfn->dev.kobj, "physfn"); 247dd7cc44dSYu Zhao 248210647afSYinghai Lu pci_stop_and_remove_bus_device(virtfn); 249dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, virtfn->bus); 250dd7cc44dSYu Zhao 251dc087f2fSJiang Liu /* balance pci_get_domain_bus_and_slot() */ 252dc087f2fSJiang Liu pci_dev_put(virtfn); 253dd7cc44dSYu Zhao pci_dev_put(dev); 254dd7cc44dSYu Zhao } 255dd7cc44dSYu Zhao 256aaee0c1fSKelsey Skunberg static ssize_t sriov_totalvfs_show(struct device *dev, 257aaee0c1fSKelsey Skunberg struct device_attribute *attr, 258aaee0c1fSKelsey Skunberg char *buf) 259aaee0c1fSKelsey Skunberg { 260aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 261aaee0c1fSKelsey Skunberg 262aaee0c1fSKelsey Skunberg return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); 263aaee0c1fSKelsey Skunberg } 264aaee0c1fSKelsey Skunberg 265aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_show(struct device *dev, 266aaee0c1fSKelsey Skunberg struct device_attribute *attr, 267aaee0c1fSKelsey Skunberg char *buf) 268aaee0c1fSKelsey Skunberg { 269aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 27035ff867bSPierre Crégut u16 num_vfs; 271aaee0c1fSKelsey Skunberg 27235ff867bSPierre Crégut /* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */ 27335ff867bSPierre Crégut device_lock(&pdev->dev); 27435ff867bSPierre Crégut num_vfs = pdev->sriov->num_VFs; 27535ff867bSPierre Crégut device_unlock(&pdev->dev); 27635ff867bSPierre Crégut 27735ff867bSPierre Crégut return sprintf(buf, "%u\n", num_vfs); 278aaee0c1fSKelsey Skunberg } 279aaee0c1fSKelsey Skunberg 280aaee0c1fSKelsey Skunberg /* 281aaee0c1fSKelsey Skunberg * num_vfs > 0; number of VFs to enable 282aaee0c1fSKelsey Skunberg * num_vfs = 0; disable all VFs 283aaee0c1fSKelsey Skunberg * 284aaee0c1fSKelsey Skunberg * Note: SRIOV spec does not allow partial VF 285aaee0c1fSKelsey Skunberg * disable, so it's all or none. 286aaee0c1fSKelsey Skunberg */ 287aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_store(struct device *dev, 288aaee0c1fSKelsey Skunberg struct device_attribute *attr, 289aaee0c1fSKelsey Skunberg const char *buf, size_t count) 290aaee0c1fSKelsey Skunberg { 291aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 292aaee0c1fSKelsey Skunberg int ret; 293aaee0c1fSKelsey Skunberg u16 num_vfs; 294aaee0c1fSKelsey Skunberg 295aaee0c1fSKelsey Skunberg ret = kstrtou16(buf, 0, &num_vfs); 296aaee0c1fSKelsey Skunberg if (ret < 0) 297aaee0c1fSKelsey Skunberg return ret; 298aaee0c1fSKelsey Skunberg 299aaee0c1fSKelsey Skunberg if (num_vfs > pci_sriov_get_totalvfs(pdev)) 300aaee0c1fSKelsey Skunberg return -ERANGE; 301aaee0c1fSKelsey Skunberg 302aaee0c1fSKelsey Skunberg device_lock(&pdev->dev); 303aaee0c1fSKelsey Skunberg 304aaee0c1fSKelsey Skunberg if (num_vfs == pdev->sriov->num_VFs) 305aaee0c1fSKelsey Skunberg goto exit; 306aaee0c1fSKelsey Skunberg 307aaee0c1fSKelsey Skunberg /* is PF driver loaded w/callback */ 308aaee0c1fSKelsey Skunberg if (!pdev->driver || !pdev->driver->sriov_configure) { 309aaee0c1fSKelsey Skunberg pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n"); 310aaee0c1fSKelsey Skunberg ret = -ENOENT; 311aaee0c1fSKelsey Skunberg goto exit; 312aaee0c1fSKelsey Skunberg } 313aaee0c1fSKelsey Skunberg 314aaee0c1fSKelsey Skunberg if (num_vfs == 0) { 315aaee0c1fSKelsey Skunberg /* disable VFs */ 316aaee0c1fSKelsey Skunberg ret = pdev->driver->sriov_configure(pdev, 0); 317aaee0c1fSKelsey Skunberg goto exit; 318aaee0c1fSKelsey Skunberg } 319aaee0c1fSKelsey Skunberg 320aaee0c1fSKelsey Skunberg /* enable VFs */ 321aaee0c1fSKelsey Skunberg if (pdev->sriov->num_VFs) { 322aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n", 323aaee0c1fSKelsey Skunberg pdev->sriov->num_VFs, num_vfs); 324aaee0c1fSKelsey Skunberg ret = -EBUSY; 325aaee0c1fSKelsey Skunberg goto exit; 326aaee0c1fSKelsey Skunberg } 327aaee0c1fSKelsey Skunberg 328aaee0c1fSKelsey Skunberg ret = pdev->driver->sriov_configure(pdev, num_vfs); 329aaee0c1fSKelsey Skunberg if (ret < 0) 330aaee0c1fSKelsey Skunberg goto exit; 331aaee0c1fSKelsey Skunberg 332aaee0c1fSKelsey Skunberg if (ret != num_vfs) 333aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs requested; only %d enabled\n", 334aaee0c1fSKelsey Skunberg num_vfs, ret); 335aaee0c1fSKelsey Skunberg 336aaee0c1fSKelsey Skunberg exit: 337aaee0c1fSKelsey Skunberg device_unlock(&pdev->dev); 338aaee0c1fSKelsey Skunberg 339aaee0c1fSKelsey Skunberg if (ret < 0) 340aaee0c1fSKelsey Skunberg return ret; 341aaee0c1fSKelsey Skunberg 342aaee0c1fSKelsey Skunberg return count; 343aaee0c1fSKelsey Skunberg } 344aaee0c1fSKelsey Skunberg 345aaee0c1fSKelsey Skunberg static ssize_t sriov_offset_show(struct device *dev, 346aaee0c1fSKelsey Skunberg struct device_attribute *attr, 347aaee0c1fSKelsey Skunberg char *buf) 348aaee0c1fSKelsey Skunberg { 349aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 350aaee0c1fSKelsey Skunberg 351aaee0c1fSKelsey Skunberg return sprintf(buf, "%u\n", pdev->sriov->offset); 352aaee0c1fSKelsey Skunberg } 353aaee0c1fSKelsey Skunberg 354aaee0c1fSKelsey Skunberg static ssize_t sriov_stride_show(struct device *dev, 355aaee0c1fSKelsey Skunberg struct device_attribute *attr, 356aaee0c1fSKelsey Skunberg char *buf) 357aaee0c1fSKelsey Skunberg { 358aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 359aaee0c1fSKelsey Skunberg 360aaee0c1fSKelsey Skunberg return sprintf(buf, "%u\n", pdev->sriov->stride); 361aaee0c1fSKelsey Skunberg } 362aaee0c1fSKelsey Skunberg 363aaee0c1fSKelsey Skunberg static ssize_t sriov_vf_device_show(struct device *dev, 364aaee0c1fSKelsey Skunberg struct device_attribute *attr, 365aaee0c1fSKelsey Skunberg char *buf) 366aaee0c1fSKelsey Skunberg { 367aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 368aaee0c1fSKelsey Skunberg 369aaee0c1fSKelsey Skunberg return sprintf(buf, "%x\n", pdev->sriov->vf_device); 370aaee0c1fSKelsey Skunberg } 371aaee0c1fSKelsey Skunberg 372aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_show(struct device *dev, 373aaee0c1fSKelsey Skunberg struct device_attribute *attr, 374aaee0c1fSKelsey Skunberg char *buf) 375aaee0c1fSKelsey Skunberg { 376aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 377aaee0c1fSKelsey Skunberg 378aaee0c1fSKelsey Skunberg return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe); 379aaee0c1fSKelsey Skunberg } 380aaee0c1fSKelsey Skunberg 381aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_store(struct device *dev, 382aaee0c1fSKelsey Skunberg struct device_attribute *attr, 383aaee0c1fSKelsey Skunberg const char *buf, size_t count) 384aaee0c1fSKelsey Skunberg { 385aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev); 386aaee0c1fSKelsey Skunberg bool drivers_autoprobe; 387aaee0c1fSKelsey Skunberg 388aaee0c1fSKelsey Skunberg if (kstrtobool(buf, &drivers_autoprobe) < 0) 389aaee0c1fSKelsey Skunberg return -EINVAL; 390aaee0c1fSKelsey Skunberg 391aaee0c1fSKelsey Skunberg pdev->sriov->drivers_autoprobe = drivers_autoprobe; 392aaee0c1fSKelsey Skunberg 393aaee0c1fSKelsey Skunberg return count; 394aaee0c1fSKelsey Skunberg } 395aaee0c1fSKelsey Skunberg 396aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_totalvfs); 397244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_numvfs); 398aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_offset); 399aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_stride); 400aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_vf_device); 401244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_drivers_autoprobe); 402aaee0c1fSKelsey Skunberg 403aaee0c1fSKelsey Skunberg static struct attribute *sriov_dev_attrs[] = { 404aaee0c1fSKelsey Skunberg &dev_attr_sriov_totalvfs.attr, 405aaee0c1fSKelsey Skunberg &dev_attr_sriov_numvfs.attr, 406aaee0c1fSKelsey Skunberg &dev_attr_sriov_offset.attr, 407aaee0c1fSKelsey Skunberg &dev_attr_sriov_stride.attr, 408aaee0c1fSKelsey Skunberg &dev_attr_sriov_vf_device.attr, 409aaee0c1fSKelsey Skunberg &dev_attr_sriov_drivers_autoprobe.attr, 410aaee0c1fSKelsey Skunberg NULL, 411aaee0c1fSKelsey Skunberg }; 412aaee0c1fSKelsey Skunberg 413aaee0c1fSKelsey Skunberg static umode_t sriov_attrs_are_visible(struct kobject *kobj, 414aaee0c1fSKelsey Skunberg struct attribute *a, int n) 415aaee0c1fSKelsey Skunberg { 416aaee0c1fSKelsey Skunberg struct device *dev = kobj_to_dev(kobj); 417aaee0c1fSKelsey Skunberg 418aaee0c1fSKelsey Skunberg if (!dev_is_pf(dev)) 419aaee0c1fSKelsey Skunberg return 0; 420aaee0c1fSKelsey Skunberg 421aaee0c1fSKelsey Skunberg return a->mode; 422aaee0c1fSKelsey Skunberg } 423aaee0c1fSKelsey Skunberg 424aaee0c1fSKelsey Skunberg const struct attribute_group sriov_dev_attr_group = { 425aaee0c1fSKelsey Skunberg .attrs = sriov_dev_attrs, 426aaee0c1fSKelsey Skunberg .is_visible = sriov_attrs_are_visible, 427aaee0c1fSKelsey Skunberg }; 428aaee0c1fSKelsey Skunberg 429995df527SWei Yang int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs) 430995df527SWei Yang { 431995df527SWei Yang return 0; 432995df527SWei Yang } 433995df527SWei Yang 434a39e3fcdSAlexander Duyck int __weak pcibios_sriov_disable(struct pci_dev *pdev) 435a39e3fcdSAlexander Duyck { 436a39e3fcdSAlexander Duyck return 0; 437a39e3fcdSAlexander Duyck } 438a39e3fcdSAlexander Duyck 43918f9e9d1SSebastian Ott static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) 44018f9e9d1SSebastian Ott { 44118f9e9d1SSebastian Ott unsigned int i; 44218f9e9d1SSebastian Ott int rc; 44318f9e9d1SSebastian Ott 444aff68a5aSSebastian Ott if (dev->no_vf_scan) 445aff68a5aSSebastian Ott return 0; 446aff68a5aSSebastian Ott 44718f9e9d1SSebastian Ott for (i = 0; i < num_vfs; i++) { 44818f9e9d1SSebastian Ott rc = pci_iov_add_virtfn(dev, i); 44918f9e9d1SSebastian Ott if (rc) 45018f9e9d1SSebastian Ott goto failed; 45118f9e9d1SSebastian Ott } 45218f9e9d1SSebastian Ott return 0; 45318f9e9d1SSebastian Ott failed: 45418f9e9d1SSebastian Ott while (i--) 45518f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 45618f9e9d1SSebastian Ott 45718f9e9d1SSebastian Ott return rc; 45818f9e9d1SSebastian Ott } 45918f9e9d1SSebastian Ott 460dd7cc44dSYu Zhao static int sriov_enable(struct pci_dev *dev, int nr_virtfn) 461dd7cc44dSYu Zhao { 462dd7cc44dSYu Zhao int rc; 4633443c382SAlexander Duyck int i; 464dd7cc44dSYu Zhao int nres; 465ce288ec3SAlexander Duyck u16 initial; 466dd7cc44dSYu Zhao struct resource *res; 467dd7cc44dSYu Zhao struct pci_dev *pdev; 468dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 469bbef98abSRam Pai int bars = 0; 470b07579c0SWei Yang int bus; 471dd7cc44dSYu Zhao 472dd7cc44dSYu Zhao if (!nr_virtfn) 473dd7cc44dSYu Zhao return 0; 474dd7cc44dSYu Zhao 4756b136724SBjorn Helgaas if (iov->num_VFs) 476dd7cc44dSYu Zhao return -EINVAL; 477dd7cc44dSYu Zhao 478dd7cc44dSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); 4796b136724SBjorn Helgaas if (initial > iov->total_VFs || 4806b136724SBjorn Helgaas (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs))) 481dd7cc44dSYu Zhao return -EIO; 482dd7cc44dSYu Zhao 4836b136724SBjorn Helgaas if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs || 484dd7cc44dSYu Zhao (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) 485dd7cc44dSYu Zhao return -EINVAL; 486dd7cc44dSYu Zhao 487dd7cc44dSYu Zhao nres = 0; 488dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 489bbef98abSRam Pai bars |= (1 << (i + PCI_IOV_RESOURCES)); 490c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 491dd7cc44dSYu Zhao if (res->parent) 492dd7cc44dSYu Zhao nres++; 493dd7cc44dSYu Zhao } 494dd7cc44dSYu Zhao if (nres != iov->nres) { 4957506dc79SFrederick Lawler pci_err(dev, "not enough MMIO resources for SR-IOV\n"); 496dd7cc44dSYu Zhao return -ENOMEM; 497dd7cc44dSYu Zhao } 498dd7cc44dSYu Zhao 499b07579c0SWei Yang bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1); 50068f8e9faSBjorn Helgaas if (bus > dev->bus->busn_res.end) { 5017506dc79SFrederick Lawler pci_err(dev, "can't enable %d VFs (bus %02x out of range of %pR)\n", 50268f8e9faSBjorn Helgaas nr_virtfn, bus, &dev->bus->busn_res); 503dd7cc44dSYu Zhao return -ENOMEM; 504dd7cc44dSYu Zhao } 505dd7cc44dSYu Zhao 506bbef98abSRam Pai if (pci_enable_resources(dev, bars)) { 5077506dc79SFrederick Lawler pci_err(dev, "SR-IOV: IOV BARS not allocated\n"); 508bbef98abSRam Pai return -ENOMEM; 509bbef98abSRam Pai } 510bbef98abSRam Pai 511dd7cc44dSYu Zhao if (iov->link != dev->devfn) { 512dd7cc44dSYu Zhao pdev = pci_get_slot(dev->bus, iov->link); 513dd7cc44dSYu Zhao if (!pdev) 514dd7cc44dSYu Zhao return -ENODEV; 515dd7cc44dSYu Zhao 516dc087f2fSJiang Liu if (!pdev->is_physfn) { 517dd7cc44dSYu Zhao pci_dev_put(pdev); 518652d1100SStefan Assmann return -ENOSYS; 519dc087f2fSJiang Liu } 520dd7cc44dSYu Zhao 521dd7cc44dSYu Zhao rc = sysfs_create_link(&dev->dev.kobj, 522dd7cc44dSYu Zhao &pdev->dev.kobj, "dep_link"); 523dc087f2fSJiang Liu pci_dev_put(pdev); 524dd7cc44dSYu Zhao if (rc) 525dd7cc44dSYu Zhao return rc; 526dd7cc44dSYu Zhao } 527dd7cc44dSYu Zhao 5286b136724SBjorn Helgaas iov->initial_VFs = initial; 529dd7cc44dSYu Zhao if (nr_virtfn < initial) 530dd7cc44dSYu Zhao initial = nr_virtfn; 531dd7cc44dSYu Zhao 532c23b6135SAlexander Duyck rc = pcibios_sriov_enable(dev, initial); 533c23b6135SAlexander Duyck if (rc) { 5347506dc79SFrederick Lawler pci_err(dev, "failure %d from pcibios_sriov_enable()\n", rc); 535c23b6135SAlexander Duyck goto err_pcibios; 536995df527SWei Yang } 537995df527SWei Yang 538f40ec3c7SGavin Shan pci_iov_set_numvfs(dev, nr_virtfn); 539f40ec3c7SGavin Shan iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; 540f40ec3c7SGavin Shan pci_cfg_access_lock(dev); 541f40ec3c7SGavin Shan pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 542f40ec3c7SGavin Shan msleep(100); 543f40ec3c7SGavin Shan pci_cfg_access_unlock(dev); 544f40ec3c7SGavin Shan 54518f9e9d1SSebastian Ott rc = sriov_add_vfs(dev, initial); 546dd7cc44dSYu Zhao if (rc) 54718f9e9d1SSebastian Ott goto err_pcibios; 548dd7cc44dSYu Zhao 549dd7cc44dSYu Zhao kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); 5506b136724SBjorn Helgaas iov->num_VFs = nr_virtfn; 551dd7cc44dSYu Zhao 552dd7cc44dSYu Zhao return 0; 553dd7cc44dSYu Zhao 554c23b6135SAlexander Duyck err_pcibios: 555dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 556fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 557dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 558dd7cc44dSYu Zhao ssleep(1); 559fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 560dd7cc44dSYu Zhao 5610fc690a7SGavin Shan pcibios_sriov_disable(dev); 5620fc690a7SGavin Shan 563dd7cc44dSYu Zhao if (iov->link != dev->devfn) 564dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 565dd7cc44dSYu Zhao 566b3908644SAlexander Duyck pci_iov_set_numvfs(dev, 0); 567dd7cc44dSYu Zhao return rc; 568dd7cc44dSYu Zhao } 569dd7cc44dSYu Zhao 57018f9e9d1SSebastian Ott static void sriov_del_vfs(struct pci_dev *dev) 57118f9e9d1SSebastian Ott { 57218f9e9d1SSebastian Ott struct pci_sriov *iov = dev->sriov; 57318f9e9d1SSebastian Ott int i; 57418f9e9d1SSebastian Ott 57518f9e9d1SSebastian Ott for (i = 0; i < iov->num_VFs; i++) 57618f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i); 57718f9e9d1SSebastian Ott } 57818f9e9d1SSebastian Ott 579dd7cc44dSYu Zhao static void sriov_disable(struct pci_dev *dev) 580dd7cc44dSYu Zhao { 581dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov; 582dd7cc44dSYu Zhao 5836b136724SBjorn Helgaas if (!iov->num_VFs) 584dd7cc44dSYu Zhao return; 585dd7cc44dSYu Zhao 58618f9e9d1SSebastian Ott sriov_del_vfs(dev); 587dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); 588fb51ccbfSJan Kiszka pci_cfg_access_lock(dev); 589dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 590dd7cc44dSYu Zhao ssleep(1); 591fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev); 592dd7cc44dSYu Zhao 5930fc690a7SGavin Shan pcibios_sriov_disable(dev); 5940fc690a7SGavin Shan 595dd7cc44dSYu Zhao if (iov->link != dev->devfn) 596dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link"); 597dd7cc44dSYu Zhao 5986b136724SBjorn Helgaas iov->num_VFs = 0; 599f59dca27SWei Yang pci_iov_set_numvfs(dev, 0); 600dd7cc44dSYu Zhao } 601dd7cc44dSYu Zhao 602d1b054daSYu Zhao static int sriov_init(struct pci_dev *dev, int pos) 603d1b054daSYu Zhao { 6040e6c9122SWei Yang int i, bar64; 605d1b054daSYu Zhao int rc; 606d1b054daSYu Zhao int nres; 607d1b054daSYu Zhao u32 pgsz; 608ea9a8854SAlexander Duyck u16 ctrl, total; 609d1b054daSYu Zhao struct pci_sriov *iov; 610d1b054daSYu Zhao struct resource *res; 611d1b054daSYu Zhao struct pci_dev *pdev; 612d1b054daSYu Zhao 613d1b054daSYu Zhao pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl); 614d1b054daSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) { 615d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0); 616d1b054daSYu Zhao ssleep(1); 617d1b054daSYu Zhao } 618d1b054daSYu Zhao 619d1b054daSYu Zhao ctrl = 0; 620d1b054daSYu Zhao list_for_each_entry(pdev, &dev->bus->devices, bus_list) 621d1b054daSYu Zhao if (pdev->is_physfn) 622d1b054daSYu Zhao goto found; 623d1b054daSYu Zhao 624d1b054daSYu Zhao pdev = NULL; 625d1b054daSYu Zhao if (pci_ari_enabled(dev->bus)) 626d1b054daSYu Zhao ctrl |= PCI_SRIOV_CTRL_ARI; 627d1b054daSYu Zhao 628d1b054daSYu Zhao found: 629d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); 630d1b054daSYu Zhao 631ff45f9ddSBen Shelton pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); 632ff45f9ddSBen Shelton if (!total) 633ff45f9ddSBen Shelton return 0; 634d1b054daSYu Zhao 635d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz); 636d1b054daSYu Zhao i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0; 637d1b054daSYu Zhao pgsz &= ~((1 << i) - 1); 638d1b054daSYu Zhao if (!pgsz) 639d1b054daSYu Zhao return -EIO; 640d1b054daSYu Zhao 641d1b054daSYu Zhao pgsz &= ~(pgsz - 1); 6428161fe91SVaidyanathan Srinivasan pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); 643d1b054daSYu Zhao 6440e6c9122SWei Yang iov = kzalloc(sizeof(*iov), GFP_KERNEL); 6450e6c9122SWei Yang if (!iov) 6460e6c9122SWei Yang return -ENOMEM; 6470e6c9122SWei Yang 648d1b054daSYu Zhao nres = 0; 649d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 650c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 65111183991SDavid Daney /* 65211183991SDavid Daney * If it is already FIXED, don't change it, something 65311183991SDavid Daney * (perhaps EA or header fixups) wants it this way. 65411183991SDavid Daney */ 65511183991SDavid Daney if (res->flags & IORESOURCE_PCI_FIXED) 65611183991SDavid Daney bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0; 65711183991SDavid Daney else 6580e6c9122SWei Yang bar64 = __pci_read_base(dev, pci_bar_unknown, res, 659d1b054daSYu Zhao pos + PCI_SRIOV_BAR + i * 4); 660d1b054daSYu Zhao if (!res->flags) 661d1b054daSYu Zhao continue; 662d1b054daSYu Zhao if (resource_size(res) & (PAGE_SIZE - 1)) { 663d1b054daSYu Zhao rc = -EIO; 664d1b054daSYu Zhao goto failed; 665d1b054daSYu Zhao } 6660e6c9122SWei Yang iov->barsz[i] = resource_size(res); 667d1b054daSYu Zhao res->end = res->start + resource_size(res) * total - 1; 6687506dc79SFrederick Lawler pci_info(dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n", 669e88ae01dSWei Yang i, res, i, total); 6700e6c9122SWei Yang i += bar64; 671d1b054daSYu Zhao nres++; 672d1b054daSYu Zhao } 673d1b054daSYu Zhao 674d1b054daSYu Zhao iov->pos = pos; 675d1b054daSYu Zhao iov->nres = nres; 676d1b054daSYu Zhao iov->ctrl = ctrl; 6776b136724SBjorn Helgaas iov->total_VFs = total; 6788d85a7a4SJakub Kicinski iov->driver_max_VFs = total; 6793142d832SFilippo Sironi pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device); 680d1b054daSYu Zhao iov->pgsz = pgsz; 681d1b054daSYu Zhao iov->self = dev; 6820e7df224SBodong Wang iov->drivers_autoprobe = true; 683d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); 684d1b054daSYu Zhao pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); 68562f87c0eSYijing Wang if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) 6864d135dbeSYu Zhao iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link); 687d1b054daSYu Zhao 688d1b054daSYu Zhao if (pdev) 689d1b054daSYu Zhao iov->dev = pci_dev_get(pdev); 690e277d2fcSYu Zhao else 691d1b054daSYu Zhao iov->dev = dev; 692e277d2fcSYu Zhao 693d1b054daSYu Zhao dev->sriov = iov; 694d1b054daSYu Zhao dev->is_physfn = 1; 695ea9a8854SAlexander Duyck rc = compute_max_vf_buses(dev); 696ea9a8854SAlexander Duyck if (rc) 697ea9a8854SAlexander Duyck goto fail_max_buses; 698d1b054daSYu Zhao 699d1b054daSYu Zhao return 0; 700d1b054daSYu Zhao 701ea9a8854SAlexander Duyck fail_max_buses: 702ea9a8854SAlexander Duyck dev->sriov = NULL; 703ea9a8854SAlexander Duyck dev->is_physfn = 0; 704d1b054daSYu Zhao failed: 705d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { 706c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES]; 707d1b054daSYu Zhao res->flags = 0; 708d1b054daSYu Zhao } 709d1b054daSYu Zhao 7100e6c9122SWei Yang kfree(iov); 711d1b054daSYu Zhao return rc; 712d1b054daSYu Zhao } 713d1b054daSYu Zhao 714d1b054daSYu Zhao static void sriov_release(struct pci_dev *dev) 715d1b054daSYu Zhao { 7166b136724SBjorn Helgaas BUG_ON(dev->sriov->num_VFs); 717dd7cc44dSYu Zhao 718e277d2fcSYu Zhao if (dev != dev->sriov->dev) 719d1b054daSYu Zhao pci_dev_put(dev->sriov->dev); 720d1b054daSYu Zhao 721d1b054daSYu Zhao kfree(dev->sriov); 722d1b054daSYu Zhao dev->sriov = NULL; 723d1b054daSYu Zhao } 724d1b054daSYu Zhao 7258c5cdb6aSYu Zhao static void sriov_restore_state(struct pci_dev *dev) 7268c5cdb6aSYu Zhao { 7278c5cdb6aSYu Zhao int i; 7288c5cdb6aSYu Zhao u16 ctrl; 7298c5cdb6aSYu Zhao struct pci_sriov *iov = dev->sriov; 7308c5cdb6aSYu Zhao 7318c5cdb6aSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl); 7328c5cdb6aSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) 7338c5cdb6aSYu Zhao return; 7348c5cdb6aSYu Zhao 735ff26449eSTony Nguyen /* 736ff26449eSTony Nguyen * Restore PCI_SRIOV_CTRL_ARI before pci_iov_set_numvfs() because 737ff26449eSTony Nguyen * it reads offset & stride, which depend on PCI_SRIOV_CTRL_ARI. 738ff26449eSTony Nguyen */ 739ff26449eSTony Nguyen ctrl &= ~PCI_SRIOV_CTRL_ARI; 740ff26449eSTony Nguyen ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI; 741ff26449eSTony Nguyen pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl); 742ff26449eSTony Nguyen 74339098edbSDenis Efremov for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) 74439098edbSDenis Efremov pci_update_resource(dev, i + PCI_IOV_RESOURCES); 7458c5cdb6aSYu Zhao 7468c5cdb6aSYu Zhao pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); 747f59dca27SWei Yang pci_iov_set_numvfs(dev, iov->num_VFs); 7488c5cdb6aSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); 7498c5cdb6aSYu Zhao if (iov->ctrl & PCI_SRIOV_CTRL_VFE) 7508c5cdb6aSYu Zhao msleep(100); 7518c5cdb6aSYu Zhao } 7528c5cdb6aSYu Zhao 753d1b054daSYu Zhao /** 754d1b054daSYu Zhao * pci_iov_init - initialize the IOV capability 755d1b054daSYu Zhao * @dev: the PCI device 756d1b054daSYu Zhao * 757d1b054daSYu Zhao * Returns 0 on success, or negative on failure. 758d1b054daSYu Zhao */ 759d1b054daSYu Zhao int pci_iov_init(struct pci_dev *dev) 760d1b054daSYu Zhao { 761d1b054daSYu Zhao int pos; 762d1b054daSYu Zhao 7635f4d91a1SKenji Kaneshige if (!pci_is_pcie(dev)) 764d1b054daSYu Zhao return -ENODEV; 765d1b054daSYu Zhao 766d1b054daSYu Zhao pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); 767d1b054daSYu Zhao if (pos) 768d1b054daSYu Zhao return sriov_init(dev, pos); 769d1b054daSYu Zhao 770d1b054daSYu Zhao return -ENODEV; 771d1b054daSYu Zhao } 772d1b054daSYu Zhao 773d1b054daSYu Zhao /** 774d1b054daSYu Zhao * pci_iov_release - release resources used by the IOV capability 775d1b054daSYu Zhao * @dev: the PCI device 776d1b054daSYu Zhao */ 777d1b054daSYu Zhao void pci_iov_release(struct pci_dev *dev) 778d1b054daSYu Zhao { 779d1b054daSYu Zhao if (dev->is_physfn) 780d1b054daSYu Zhao sriov_release(dev); 781d1b054daSYu Zhao } 782d1b054daSYu Zhao 783d1b054daSYu Zhao /** 78438972375SJakub Kicinski * pci_iov_remove - clean up SR-IOV state after PF driver is detached 78538972375SJakub Kicinski * @dev: the PCI device 78638972375SJakub Kicinski */ 78738972375SJakub Kicinski void pci_iov_remove(struct pci_dev *dev) 78838972375SJakub Kicinski { 78938972375SJakub Kicinski struct pci_sriov *iov = dev->sriov; 79038972375SJakub Kicinski 79138972375SJakub Kicinski if (!dev->is_physfn) 79238972375SJakub Kicinski return; 79338972375SJakub Kicinski 79438972375SJakub Kicinski iov->driver_max_VFs = iov->total_VFs; 79538972375SJakub Kicinski if (iov->num_VFs) 79638972375SJakub Kicinski pci_warn(dev, "driver left SR-IOV enabled after remove\n"); 79738972375SJakub Kicinski } 79838972375SJakub Kicinski 79938972375SJakub Kicinski /** 8006ffa2489SBjorn Helgaas * pci_iov_update_resource - update a VF BAR 8016ffa2489SBjorn Helgaas * @dev: the PCI device 8026ffa2489SBjorn Helgaas * @resno: the resource number 8036ffa2489SBjorn Helgaas * 8046ffa2489SBjorn Helgaas * Update a VF BAR in the SR-IOV capability of a PF. 8056ffa2489SBjorn Helgaas */ 8066ffa2489SBjorn Helgaas void pci_iov_update_resource(struct pci_dev *dev, int resno) 8076ffa2489SBjorn Helgaas { 8086ffa2489SBjorn Helgaas struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; 8096ffa2489SBjorn Helgaas struct resource *res = dev->resource + resno; 8106ffa2489SBjorn Helgaas int vf_bar = resno - PCI_IOV_RESOURCES; 8116ffa2489SBjorn Helgaas struct pci_bus_region region; 812546ba9f8SBjorn Helgaas u16 cmd; 8136ffa2489SBjorn Helgaas u32 new; 8146ffa2489SBjorn Helgaas int reg; 8156ffa2489SBjorn Helgaas 8166ffa2489SBjorn Helgaas /* 8176ffa2489SBjorn Helgaas * The generic pci_restore_bars() path calls this for all devices, 8186ffa2489SBjorn Helgaas * including VFs and non-SR-IOV devices. If this is not a PF, we 8196ffa2489SBjorn Helgaas * have nothing to do. 8206ffa2489SBjorn Helgaas */ 8216ffa2489SBjorn Helgaas if (!iov) 8226ffa2489SBjorn Helgaas return; 8236ffa2489SBjorn Helgaas 824546ba9f8SBjorn Helgaas pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); 825546ba9f8SBjorn Helgaas if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { 826546ba9f8SBjorn Helgaas dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", 827546ba9f8SBjorn Helgaas vf_bar, res); 828546ba9f8SBjorn Helgaas return; 829546ba9f8SBjorn Helgaas } 830546ba9f8SBjorn Helgaas 8316ffa2489SBjorn Helgaas /* 8326ffa2489SBjorn Helgaas * Ignore unimplemented BARs, unused resource slots for 64-bit 8336ffa2489SBjorn Helgaas * BARs, and non-movable resources, e.g., those described via 8346ffa2489SBjorn Helgaas * Enhanced Allocation. 8356ffa2489SBjorn Helgaas */ 8366ffa2489SBjorn Helgaas if (!res->flags) 8376ffa2489SBjorn Helgaas return; 8386ffa2489SBjorn Helgaas 8396ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_UNSET) 8406ffa2489SBjorn Helgaas return; 8416ffa2489SBjorn Helgaas 8426ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_PCI_FIXED) 8436ffa2489SBjorn Helgaas return; 8446ffa2489SBjorn Helgaas 8456ffa2489SBjorn Helgaas pcibios_resource_to_bus(dev->bus, ®ion, res); 8466ffa2489SBjorn Helgaas new = region.start; 8476ffa2489SBjorn Helgaas new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; 8486ffa2489SBjorn Helgaas 8496ffa2489SBjorn Helgaas reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar; 8506ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg, new); 8516ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_MEM_64) { 8526ffa2489SBjorn Helgaas new = region.start >> 16 >> 16; 8536ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg + 4, new); 8546ffa2489SBjorn Helgaas } 8556ffa2489SBjorn Helgaas } 8566ffa2489SBjorn Helgaas 857978d2d68SWei Yang resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev, 858978d2d68SWei Yang int resno) 859978d2d68SWei Yang { 860978d2d68SWei Yang return pci_iov_resource_size(dev, resno); 861978d2d68SWei Yang } 862978d2d68SWei Yang 8638c5cdb6aSYu Zhao /** 8646faf17f6SChris Wright * pci_sriov_resource_alignment - get resource alignment for VF BAR 8656faf17f6SChris Wright * @dev: the PCI device 8666faf17f6SChris Wright * @resno: the resource number 8676faf17f6SChris Wright * 8686faf17f6SChris Wright * Returns the alignment of the VF BAR found in the SR-IOV capability. 8696faf17f6SChris Wright * This is not the same as the resource size which is defined as 8706faf17f6SChris Wright * the VF BAR size multiplied by the number of VFs. The alignment 8716faf17f6SChris Wright * is just the VF BAR size. 8726faf17f6SChris Wright */ 8730e52247aSCam Macdonell resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) 8746faf17f6SChris Wright { 875978d2d68SWei Yang return pcibios_iov_resource_alignment(dev, resno); 8766faf17f6SChris Wright } 8776faf17f6SChris Wright 8786faf17f6SChris Wright /** 8798c5cdb6aSYu Zhao * pci_restore_iov_state - restore the state of the IOV capability 8808c5cdb6aSYu Zhao * @dev: the PCI device 8818c5cdb6aSYu Zhao */ 8828c5cdb6aSYu Zhao void pci_restore_iov_state(struct pci_dev *dev) 8838c5cdb6aSYu Zhao { 8848c5cdb6aSYu Zhao if (dev->is_physfn) 8858c5cdb6aSYu Zhao sriov_restore_state(dev); 8868c5cdb6aSYu Zhao } 887a28724b0SYu Zhao 888a28724b0SYu Zhao /** 889608c0d88SBryant G. Ly * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs 890608c0d88SBryant G. Ly * @dev: the PCI device 891608c0d88SBryant G. Ly * @auto_probe: set VF drivers auto probe flag 892608c0d88SBryant G. Ly */ 893608c0d88SBryant G. Ly void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe) 894608c0d88SBryant G. Ly { 895608c0d88SBryant G. Ly if (dev->is_physfn) 896608c0d88SBryant G. Ly dev->sriov->drivers_autoprobe = auto_probe; 897608c0d88SBryant G. Ly } 898608c0d88SBryant G. Ly 899608c0d88SBryant G. Ly /** 900a28724b0SYu Zhao * pci_iov_bus_range - find bus range used by Virtual Function 901a28724b0SYu Zhao * @bus: the PCI bus 902a28724b0SYu Zhao * 903a28724b0SYu Zhao * Returns max number of buses (exclude current one) used by Virtual 904a28724b0SYu Zhao * Functions. 905a28724b0SYu Zhao */ 906a28724b0SYu Zhao int pci_iov_bus_range(struct pci_bus *bus) 907a28724b0SYu Zhao { 908a28724b0SYu Zhao int max = 0; 909a28724b0SYu Zhao struct pci_dev *dev; 910a28724b0SYu Zhao 911a28724b0SYu Zhao list_for_each_entry(dev, &bus->devices, bus_list) { 912a28724b0SYu Zhao if (!dev->is_physfn) 913a28724b0SYu Zhao continue; 9144449f079SWei Yang if (dev->sriov->max_VF_buses > max) 9154449f079SWei Yang max = dev->sriov->max_VF_buses; 916a28724b0SYu Zhao } 917a28724b0SYu Zhao 918a28724b0SYu Zhao return max ? max - bus->number : 0; 919a28724b0SYu Zhao } 920dd7cc44dSYu Zhao 921dd7cc44dSYu Zhao /** 922dd7cc44dSYu Zhao * pci_enable_sriov - enable the SR-IOV capability 923dd7cc44dSYu Zhao * @dev: the PCI device 92452a8873bSRandy Dunlap * @nr_virtfn: number of virtual functions to enable 925dd7cc44dSYu Zhao * 926dd7cc44dSYu Zhao * Returns 0 on success, or negative on failure. 927dd7cc44dSYu Zhao */ 928dd7cc44dSYu Zhao int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) 929dd7cc44dSYu Zhao { 930dd7cc44dSYu Zhao might_sleep(); 931dd7cc44dSYu Zhao 932dd7cc44dSYu Zhao if (!dev->is_physfn) 933652d1100SStefan Assmann return -ENOSYS; 934dd7cc44dSYu Zhao 935dd7cc44dSYu Zhao return sriov_enable(dev, nr_virtfn); 936dd7cc44dSYu Zhao } 937dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_enable_sriov); 938dd7cc44dSYu Zhao 939dd7cc44dSYu Zhao /** 940dd7cc44dSYu Zhao * pci_disable_sriov - disable the SR-IOV capability 941dd7cc44dSYu Zhao * @dev: the PCI device 942dd7cc44dSYu Zhao */ 943dd7cc44dSYu Zhao void pci_disable_sriov(struct pci_dev *dev) 944dd7cc44dSYu Zhao { 945dd7cc44dSYu Zhao might_sleep(); 946dd7cc44dSYu Zhao 947dd7cc44dSYu Zhao if (!dev->is_physfn) 948dd7cc44dSYu Zhao return; 949dd7cc44dSYu Zhao 950dd7cc44dSYu Zhao sriov_disable(dev); 951dd7cc44dSYu Zhao } 952dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_disable_sriov); 95374bb1bccSYu Zhao 95474bb1bccSYu Zhao /** 955fb8a0d9dSWilliams, Mitch A * pci_num_vf - return number of VFs associated with a PF device_release_driver 956fb8a0d9dSWilliams, Mitch A * @dev: the PCI device 957fb8a0d9dSWilliams, Mitch A * 958fb8a0d9dSWilliams, Mitch A * Returns number of VFs, or 0 if SR-IOV is not enabled. 959fb8a0d9dSWilliams, Mitch A */ 960fb8a0d9dSWilliams, Mitch A int pci_num_vf(struct pci_dev *dev) 961fb8a0d9dSWilliams, Mitch A { 9621452cd76SBjorn Helgaas if (!dev->is_physfn) 963fb8a0d9dSWilliams, Mitch A return 0; 9641452cd76SBjorn Helgaas 9656b136724SBjorn Helgaas return dev->sriov->num_VFs; 966fb8a0d9dSWilliams, Mitch A } 967fb8a0d9dSWilliams, Mitch A EXPORT_SYMBOL_GPL(pci_num_vf); 968bff73156SDonald Dutile 969bff73156SDonald Dutile /** 9705a8eb242SAlexander Duyck * pci_vfs_assigned - returns number of VFs are assigned to a guest 9715a8eb242SAlexander Duyck * @dev: the PCI device 9725a8eb242SAlexander Duyck * 9735a8eb242SAlexander Duyck * Returns number of VFs belonging to this device that are assigned to a guest. 974652d1100SStefan Assmann * If device is not a physical function returns 0. 9755a8eb242SAlexander Duyck */ 9765a8eb242SAlexander Duyck int pci_vfs_assigned(struct pci_dev *dev) 9775a8eb242SAlexander Duyck { 9785a8eb242SAlexander Duyck struct pci_dev *vfdev; 9795a8eb242SAlexander Duyck unsigned int vfs_assigned = 0; 9805a8eb242SAlexander Duyck unsigned short dev_id; 9815a8eb242SAlexander Duyck 9825a8eb242SAlexander Duyck /* only search if we are a PF */ 9835a8eb242SAlexander Duyck if (!dev->is_physfn) 9845a8eb242SAlexander Duyck return 0; 9855a8eb242SAlexander Duyck 9865a8eb242SAlexander Duyck /* 9875a8eb242SAlexander Duyck * determine the device ID for the VFs, the vendor ID will be the 9885a8eb242SAlexander Duyck * same as the PF so there is no need to check for that one 9895a8eb242SAlexander Duyck */ 9903142d832SFilippo Sironi dev_id = dev->sriov->vf_device; 9915a8eb242SAlexander Duyck 9925a8eb242SAlexander Duyck /* loop through all the VFs to see if we own any that are assigned */ 9935a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, NULL); 9945a8eb242SAlexander Duyck while (vfdev) { 9955a8eb242SAlexander Duyck /* 9965a8eb242SAlexander Duyck * It is considered assigned if it is a virtual function with 9975a8eb242SAlexander Duyck * our dev as the physical function and the assigned bit is set 9985a8eb242SAlexander Duyck */ 9995a8eb242SAlexander Duyck if (vfdev->is_virtfn && (vfdev->physfn == dev) && 1000be63497cSEthan Zhao pci_is_dev_assigned(vfdev)) 10015a8eb242SAlexander Duyck vfs_assigned++; 10025a8eb242SAlexander Duyck 10035a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, vfdev); 10045a8eb242SAlexander Duyck } 10055a8eb242SAlexander Duyck 10065a8eb242SAlexander Duyck return vfs_assigned; 10075a8eb242SAlexander Duyck } 10085a8eb242SAlexander Duyck EXPORT_SYMBOL_GPL(pci_vfs_assigned); 10095a8eb242SAlexander Duyck 10105a8eb242SAlexander Duyck /** 1011bff73156SDonald Dutile * pci_sriov_set_totalvfs -- reduce the TotalVFs available 1012bff73156SDonald Dutile * @dev: the PCI PF device 10132094f167SRandy Dunlap * @numvfs: number that should be used for TotalVFs supported 1014bff73156SDonald Dutile * 1015bff73156SDonald Dutile * Should be called from PF driver's probe routine with 1016bff73156SDonald Dutile * device's mutex held. 1017bff73156SDonald Dutile * 1018bff73156SDonald Dutile * Returns 0 if PF is an SRIOV-capable device and 1019652d1100SStefan Assmann * value of numvfs valid. If not a PF return -ENOSYS; 1020652d1100SStefan Assmann * if numvfs is invalid return -EINVAL; 1021bff73156SDonald Dutile * if VFs already enabled, return -EBUSY. 1022bff73156SDonald Dutile */ 1023bff73156SDonald Dutile int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) 1024bff73156SDonald Dutile { 1025652d1100SStefan Assmann if (!dev->is_physfn) 1026652d1100SStefan Assmann return -ENOSYS; 102751259d00SBjorn Helgaas 1028652d1100SStefan Assmann if (numvfs > dev->sriov->total_VFs) 1029bff73156SDonald Dutile return -EINVAL; 1030bff73156SDonald Dutile 1031bff73156SDonald Dutile /* Shouldn't change if VFs already enabled */ 1032bff73156SDonald Dutile if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) 1033bff73156SDonald Dutile return -EBUSY; 1034bff73156SDonald Dutile 103551259d00SBjorn Helgaas dev->sriov->driver_max_VFs = numvfs; 1036bff73156SDonald Dutile return 0; 1037bff73156SDonald Dutile } 1038bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); 1039bff73156SDonald Dutile 1040bff73156SDonald Dutile /** 1041ddc191f5SJonghwan Choi * pci_sriov_get_totalvfs -- get total VFs supported on this device 1042bff73156SDonald Dutile * @dev: the PCI PF device 1043bff73156SDonald Dutile * 1044bff73156SDonald Dutile * For a PCIe device with SRIOV support, return the PCIe 10456b136724SBjorn Helgaas * SRIOV capability value of TotalVFs or the value of driver_max_VFs 1046652d1100SStefan Assmann * if the driver reduced it. Otherwise 0. 1047bff73156SDonald Dutile */ 1048bff73156SDonald Dutile int pci_sriov_get_totalvfs(struct pci_dev *dev) 1049bff73156SDonald Dutile { 10501452cd76SBjorn Helgaas if (!dev->is_physfn) 1051652d1100SStefan Assmann return 0; 1052bff73156SDonald Dutile 10536b136724SBjorn Helgaas return dev->sriov->driver_max_VFs; 1054bff73156SDonald Dutile } 1055bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); 10568effc395SAlexander Duyck 10578effc395SAlexander Duyck /** 10588effc395SAlexander Duyck * pci_sriov_configure_simple - helper to configure SR-IOV 10598effc395SAlexander Duyck * @dev: the PCI device 10608effc395SAlexander Duyck * @nr_virtfn: number of virtual functions to enable, 0 to disable 10618effc395SAlexander Duyck * 10628effc395SAlexander Duyck * Enable or disable SR-IOV for devices that don't require any PF setup 10638effc395SAlexander Duyck * before enabling SR-IOV. Return value is negative on error, or number of 10648effc395SAlexander Duyck * VFs allocated on success. 10658effc395SAlexander Duyck */ 10668effc395SAlexander Duyck int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn) 10678effc395SAlexander Duyck { 10688effc395SAlexander Duyck int rc; 10698effc395SAlexander Duyck 10708effc395SAlexander Duyck might_sleep(); 10718effc395SAlexander Duyck 10728effc395SAlexander Duyck if (!dev->is_physfn) 10738effc395SAlexander Duyck return -ENODEV; 10748effc395SAlexander Duyck 10758effc395SAlexander Duyck if (pci_vfs_assigned(dev)) { 10768effc395SAlexander Duyck pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n"); 10778effc395SAlexander Duyck return -EPERM; 10788effc395SAlexander Duyck } 10798effc395SAlexander Duyck 10808effc395SAlexander Duyck if (nr_virtfn == 0) { 10818effc395SAlexander Duyck sriov_disable(dev); 10828effc395SAlexander Duyck return 0; 10838effc395SAlexander Duyck } 10848effc395SAlexander Duyck 10858effc395SAlexander Duyck rc = sriov_enable(dev, nr_virtfn); 10868effc395SAlexander Duyck if (rc < 0) 10878effc395SAlexander Duyck return rc; 10888effc395SAlexander Duyck 10898effc395SAlexander Duyck return nr_virtfn; 10908effc395SAlexander Duyck } 10918effc395SAlexander Duyck EXPORT_SYMBOL_GPL(pci_sriov_configure_simple); 1092