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
17ea0b5aa5SAlexey V. Vissarionov #define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */
18d1b054daSYu Zhao
pci_iov_virtfn_bus(struct pci_dev * dev,int vf_id)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
pci_iov_virtfn_devfn(struct pci_dev * dev,int vf_id)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
pci_iov_vf_id(struct pci_dev * dev)3621ca9fb6SJason Gunthorpe int pci_iov_vf_id(struct pci_dev *dev)
3721ca9fb6SJason Gunthorpe {
3821ca9fb6SJason Gunthorpe struct pci_dev *pf;
3921ca9fb6SJason Gunthorpe
4021ca9fb6SJason Gunthorpe if (!dev->is_virtfn)
4121ca9fb6SJason Gunthorpe return -EINVAL;
4221ca9fb6SJason Gunthorpe
4321ca9fb6SJason Gunthorpe pf = pci_physfn(dev);
446f7dc307SXiongfeng Wang return (pci_dev_id(dev) - (pci_dev_id(pf) + pf->sriov->offset)) /
4521ca9fb6SJason Gunthorpe pf->sriov->stride;
4621ca9fb6SJason Gunthorpe }
4721ca9fb6SJason Gunthorpe EXPORT_SYMBOL_GPL(pci_iov_vf_id);
4821ca9fb6SJason Gunthorpe
49a7e9f240SJason Gunthorpe /**
50a7e9f240SJason Gunthorpe * pci_iov_get_pf_drvdata - Return the drvdata of a PF
518d26c432SLeon Romanovsky * @dev: VF pci_dev
528d26c432SLeon Romanovsky * @pf_driver: Device driver required to own the PF
53a7e9f240SJason Gunthorpe *
54a7e9f240SJason Gunthorpe * This must be called from a context that ensures that a VF driver is attached.
55a7e9f240SJason Gunthorpe * The value returned is invalid once the VF driver completes its remove()
56a7e9f240SJason Gunthorpe * callback.
57a7e9f240SJason Gunthorpe *
58a7e9f240SJason Gunthorpe * Locking is achieved by the driver core. A VF driver cannot be probed until
59a7e9f240SJason Gunthorpe * pci_enable_sriov() is called and pci_disable_sriov() does not return until
60a7e9f240SJason Gunthorpe * all VF drivers have completed their remove().
61a7e9f240SJason Gunthorpe *
62a7e9f240SJason Gunthorpe * The PF driver must call pci_disable_sriov() before it begins to destroy the
63a7e9f240SJason Gunthorpe * drvdata.
64a7e9f240SJason Gunthorpe */
pci_iov_get_pf_drvdata(struct pci_dev * dev,struct pci_driver * pf_driver)65a7e9f240SJason Gunthorpe void *pci_iov_get_pf_drvdata(struct pci_dev *dev, struct pci_driver *pf_driver)
66a7e9f240SJason Gunthorpe {
67a7e9f240SJason Gunthorpe struct pci_dev *pf_dev;
68a7e9f240SJason Gunthorpe
69a7e9f240SJason Gunthorpe if (!dev->is_virtfn)
70a7e9f240SJason Gunthorpe return ERR_PTR(-EINVAL);
71a7e9f240SJason Gunthorpe pf_dev = dev->physfn;
72a7e9f240SJason Gunthorpe if (pf_dev->driver != pf_driver)
73a7e9f240SJason Gunthorpe return ERR_PTR(-EINVAL);
74a7e9f240SJason Gunthorpe return pci_get_drvdata(pf_dev);
75a7e9f240SJason Gunthorpe }
76a7e9f240SJason Gunthorpe EXPORT_SYMBOL_GPL(pci_iov_get_pf_drvdata);
77a7e9f240SJason Gunthorpe
78f59dca27SWei Yang /*
79f59dca27SWei Yang * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may
80f59dca27SWei Yang * change when NumVFs changes.
81f59dca27SWei Yang *
82f59dca27SWei Yang * Update iov->offset and iov->stride when NumVFs is written.
83f59dca27SWei Yang */
pci_iov_set_numvfs(struct pci_dev * dev,int nr_virtfn)84f59dca27SWei Yang static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn)
85f59dca27SWei Yang {
86f59dca27SWei Yang struct pci_sriov *iov = dev->sriov;
87f59dca27SWei Yang
88f59dca27SWei Yang pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
89f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &iov->offset);
90f59dca27SWei Yang pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
91f59dca27SWei Yang }
92f59dca27SWei Yang
934449f079SWei Yang /*
944449f079SWei Yang * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride
954449f079SWei Yang * determine how many additional bus numbers will be consumed by VFs.
964449f079SWei Yang *
97ea9a8854SAlexander Duyck * Iterate over all valid NumVFs, validate offset and stride, and calculate
98ea9a8854SAlexander Duyck * the maximum number of bus numbers that could ever be required.
994449f079SWei Yang */
compute_max_vf_buses(struct pci_dev * dev)100ea9a8854SAlexander Duyck static int compute_max_vf_buses(struct pci_dev *dev)
1014449f079SWei Yang {
1024449f079SWei Yang struct pci_sriov *iov = dev->sriov;
103ea9a8854SAlexander Duyck int nr_virtfn, busnr, rc = 0;
1044449f079SWei Yang
105ea9a8854SAlexander Duyck for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) {
1064449f079SWei Yang pci_iov_set_numvfs(dev, nr_virtfn);
107ea9a8854SAlexander Duyck if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) {
108ea9a8854SAlexander Duyck rc = -EIO;
109ea9a8854SAlexander Duyck goto out;
1104449f079SWei Yang }
1114449f079SWei Yang
112ea9a8854SAlexander Duyck busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1);
113ea9a8854SAlexander Duyck if (busnr > iov->max_VF_buses)
114ea9a8854SAlexander Duyck iov->max_VF_buses = busnr;
115ea9a8854SAlexander Duyck }
116ea9a8854SAlexander Duyck
117ea9a8854SAlexander Duyck out:
118ea9a8854SAlexander Duyck pci_iov_set_numvfs(dev, 0);
119ea9a8854SAlexander Duyck return rc;
1204449f079SWei Yang }
1214449f079SWei Yang
virtfn_add_bus(struct pci_bus * bus,int busnr)122dd7cc44dSYu Zhao static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
123dd7cc44dSYu Zhao {
124dd7cc44dSYu Zhao struct pci_bus *child;
125dd7cc44dSYu Zhao
126dd7cc44dSYu Zhao if (bus->number == busnr)
127dd7cc44dSYu Zhao return bus;
128dd7cc44dSYu Zhao
129dd7cc44dSYu Zhao child = pci_find_bus(pci_domain_nr(bus), busnr);
130dd7cc44dSYu Zhao if (child)
131dd7cc44dSYu Zhao return child;
132dd7cc44dSYu Zhao
133dd7cc44dSYu Zhao child = pci_add_new_bus(bus, NULL, busnr);
134dd7cc44dSYu Zhao if (!child)
135dd7cc44dSYu Zhao return NULL;
136dd7cc44dSYu Zhao
137b7eac055SYinghai Lu pci_bus_insert_busn_res(child, busnr, busnr);
138dd7cc44dSYu Zhao
139dd7cc44dSYu Zhao return child;
140dd7cc44dSYu Zhao }
141dd7cc44dSYu Zhao
virtfn_remove_bus(struct pci_bus * physbus,struct pci_bus * virtbus)142dc087f2fSJiang Liu static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
143dd7cc44dSYu Zhao {
144dc087f2fSJiang Liu if (physbus != virtbus && list_empty(&virtbus->devices))
145dc087f2fSJiang Liu pci_remove_bus(virtbus);
146dd7cc44dSYu Zhao }
147dd7cc44dSYu Zhao
pci_iov_resource_size(struct pci_dev * dev,int resno)1480e6c9122SWei Yang resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
1490e6c9122SWei Yang {
1500e6c9122SWei Yang if (!dev->is_physfn)
1510e6c9122SWei Yang return 0;
1520e6c9122SWei Yang
1530e6c9122SWei Yang return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
1540e6c9122SWei Yang }
1550e6c9122SWei Yang
pci_read_vf_config_common(struct pci_dev * virtfn)156cf0921beSKarimAllah Ahmed static void pci_read_vf_config_common(struct pci_dev *virtfn)
157cf0921beSKarimAllah Ahmed {
158cf0921beSKarimAllah Ahmed struct pci_dev *physfn = virtfn->physfn;
159cf0921beSKarimAllah Ahmed
160cf0921beSKarimAllah Ahmed /*
161cf0921beSKarimAllah Ahmed * Some config registers are the same across all associated VFs.
162cf0921beSKarimAllah Ahmed * Read them once from VF0 so we can skip reading them from the
163cf0921beSKarimAllah Ahmed * other VFs.
164cf0921beSKarimAllah Ahmed *
165cf0921beSKarimAllah Ahmed * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to
166cf0921beSKarimAllah Ahmed * have the same Revision ID and Subsystem ID, but we assume they
167cf0921beSKarimAllah Ahmed * do.
168cf0921beSKarimAllah Ahmed */
169cf0921beSKarimAllah Ahmed pci_read_config_dword(virtfn, PCI_CLASS_REVISION,
170cf0921beSKarimAllah Ahmed &physfn->sriov->class);
171cf0921beSKarimAllah Ahmed pci_read_config_byte(virtfn, PCI_HEADER_TYPE,
172cf0921beSKarimAllah Ahmed &physfn->sriov->hdr_type);
173cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID,
174cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_vendor);
175cf0921beSKarimAllah Ahmed pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
176cf0921beSKarimAllah Ahmed &physfn->sriov->subsystem_device);
177cf0921beSKarimAllah Ahmed }
178cf0921beSKarimAllah Ahmed
pci_iov_sysfs_link(struct pci_dev * dev,struct pci_dev * virtfn,int id)179a1ceea67SNiklas Schnelle int pci_iov_sysfs_link(struct pci_dev *dev,
180a1ceea67SNiklas Schnelle struct pci_dev *virtfn, int id)
181a1ceea67SNiklas Schnelle {
182a1ceea67SNiklas Schnelle char buf[VIRTFN_ID_LEN];
183a1ceea67SNiklas Schnelle int rc;
184a1ceea67SNiklas Schnelle
185a1ceea67SNiklas Schnelle sprintf(buf, "virtfn%u", id);
186a1ceea67SNiklas Schnelle rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
187a1ceea67SNiklas Schnelle if (rc)
188a1ceea67SNiklas Schnelle goto failed;
189a1ceea67SNiklas Schnelle rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
190a1ceea67SNiklas Schnelle if (rc)
191a1ceea67SNiklas Schnelle goto failed1;
192a1ceea67SNiklas Schnelle
193a1ceea67SNiklas Schnelle kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
194a1ceea67SNiklas Schnelle
195a1ceea67SNiklas Schnelle return 0;
196a1ceea67SNiklas Schnelle
197a1ceea67SNiklas Schnelle failed1:
198a1ceea67SNiklas Schnelle sysfs_remove_link(&dev->dev.kobj, buf);
199a1ceea67SNiklas Schnelle failed:
200a1ceea67SNiklas Schnelle return rc;
201a1ceea67SNiklas Schnelle }
202a1ceea67SNiklas Schnelle
203c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI
sriov_vf_total_msix_show(struct device * dev,struct device_attribute * attr,char * buf)204c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_total_msix_show(struct device *dev,
205c3d5c2d9SLeon Romanovsky struct device_attribute *attr,
206c3d5c2d9SLeon Romanovsky char *buf)
207c3d5c2d9SLeon Romanovsky {
208c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev);
209c3d5c2d9SLeon Romanovsky u32 vf_total_msix = 0;
210c3d5c2d9SLeon Romanovsky
211c3d5c2d9SLeon Romanovsky device_lock(dev);
212e0217c5bSBjorn Helgaas if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix)
213c3d5c2d9SLeon Romanovsky goto unlock;
214c3d5c2d9SLeon Romanovsky
215e0217c5bSBjorn Helgaas vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev);
216c3d5c2d9SLeon Romanovsky unlock:
217c3d5c2d9SLeon Romanovsky device_unlock(dev);
218c3d5c2d9SLeon Romanovsky return sysfs_emit(buf, "%u\n", vf_total_msix);
219c3d5c2d9SLeon Romanovsky }
220c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_RO(sriov_vf_total_msix);
221c3d5c2d9SLeon Romanovsky
sriov_vf_msix_count_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)222c3d5c2d9SLeon Romanovsky static ssize_t sriov_vf_msix_count_store(struct device *dev,
223c3d5c2d9SLeon Romanovsky struct device_attribute *attr,
224c3d5c2d9SLeon Romanovsky const char *buf, size_t count)
225c3d5c2d9SLeon Romanovsky {
226c3d5c2d9SLeon Romanovsky struct pci_dev *vf_dev = to_pci_dev(dev);
227c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = pci_physfn(vf_dev);
22836f354ecSKrzysztof Wilczyński int val, ret = 0;
229c3d5c2d9SLeon Romanovsky
23036f354ecSKrzysztof Wilczyński if (kstrtoint(buf, 0, &val) < 0)
23136f354ecSKrzysztof Wilczyński return -EINVAL;
232c3d5c2d9SLeon Romanovsky
233c3d5c2d9SLeon Romanovsky if (val < 0)
234c3d5c2d9SLeon Romanovsky return -EINVAL;
235c3d5c2d9SLeon Romanovsky
236c3d5c2d9SLeon Romanovsky device_lock(&pdev->dev);
237e0217c5bSBjorn Helgaas if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) {
238c3d5c2d9SLeon Romanovsky ret = -EOPNOTSUPP;
239c3d5c2d9SLeon Romanovsky goto err_pdev;
240c3d5c2d9SLeon Romanovsky }
241c3d5c2d9SLeon Romanovsky
242c3d5c2d9SLeon Romanovsky device_lock(&vf_dev->dev);
243e0217c5bSBjorn Helgaas if (vf_dev->driver) {
244c3d5c2d9SLeon Romanovsky /*
245c3d5c2d9SLeon Romanovsky * A driver is already attached to this VF and has configured
246c3d5c2d9SLeon Romanovsky * itself based on the current MSI-X vector count. Changing
247c3d5c2d9SLeon Romanovsky * the vector size could mess up the driver, so block it.
248c3d5c2d9SLeon Romanovsky */
249c3d5c2d9SLeon Romanovsky ret = -EBUSY;
250c3d5c2d9SLeon Romanovsky goto err_dev;
251c3d5c2d9SLeon Romanovsky }
252c3d5c2d9SLeon Romanovsky
253e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val);
254c3d5c2d9SLeon Romanovsky
255c3d5c2d9SLeon Romanovsky err_dev:
256c3d5c2d9SLeon Romanovsky device_unlock(&vf_dev->dev);
257c3d5c2d9SLeon Romanovsky err_pdev:
258c3d5c2d9SLeon Romanovsky device_unlock(&pdev->dev);
259c3d5c2d9SLeon Romanovsky return ret ? : count;
260c3d5c2d9SLeon Romanovsky }
261c3d5c2d9SLeon Romanovsky static DEVICE_ATTR_WO(sriov_vf_msix_count);
262c3d5c2d9SLeon Romanovsky #endif
263c3d5c2d9SLeon Romanovsky
264c3d5c2d9SLeon Romanovsky static struct attribute *sriov_vf_dev_attrs[] = {
265c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI
266c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_msix_count.attr,
267c3d5c2d9SLeon Romanovsky #endif
268c3d5c2d9SLeon Romanovsky NULL,
269c3d5c2d9SLeon Romanovsky };
270c3d5c2d9SLeon Romanovsky
sriov_vf_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)271c3d5c2d9SLeon Romanovsky static umode_t sriov_vf_attrs_are_visible(struct kobject *kobj,
272c3d5c2d9SLeon Romanovsky struct attribute *a, int n)
273c3d5c2d9SLeon Romanovsky {
274c3d5c2d9SLeon Romanovsky struct device *dev = kobj_to_dev(kobj);
275c3d5c2d9SLeon Romanovsky struct pci_dev *pdev = to_pci_dev(dev);
276c3d5c2d9SLeon Romanovsky
277c3d5c2d9SLeon Romanovsky if (!pdev->is_virtfn)
278c3d5c2d9SLeon Romanovsky return 0;
279c3d5c2d9SLeon Romanovsky
280c3d5c2d9SLeon Romanovsky return a->mode;
281c3d5c2d9SLeon Romanovsky }
282c3d5c2d9SLeon Romanovsky
283c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_vf_dev_attr_group = {
284c3d5c2d9SLeon Romanovsky .attrs = sriov_vf_dev_attrs,
285c3d5c2d9SLeon Romanovsky .is_visible = sriov_vf_attrs_are_visible,
286c3d5c2d9SLeon Romanovsky };
287c3d5c2d9SLeon Romanovsky
pci_iov_add_virtfn(struct pci_dev * dev,int id)288753f6124SJan H. Schönherr int pci_iov_add_virtfn(struct pci_dev *dev, int id)
289dd7cc44dSYu Zhao {
290dd7cc44dSYu Zhao int i;
291dc087f2fSJiang Liu int rc = -ENOMEM;
292dd7cc44dSYu Zhao u64 size;
293dd7cc44dSYu Zhao struct pci_dev *virtfn;
294dd7cc44dSYu Zhao struct resource *res;
295dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov;
2968b1fce04SGu Zheng struct pci_bus *bus;
297dd7cc44dSYu Zhao
298b07579c0SWei Yang bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
299dc087f2fSJiang Liu if (!bus)
300dc087f2fSJiang Liu goto failed;
301dc087f2fSJiang Liu
302dc087f2fSJiang Liu virtfn = pci_alloc_dev(bus);
303dc087f2fSJiang Liu if (!virtfn)
304dc087f2fSJiang Liu goto failed0;
305dc087f2fSJiang Liu
306b07579c0SWei Yang virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
307dd7cc44dSYu Zhao virtfn->vendor = dev->vendor;
3083142d832SFilippo Sironi virtfn->device = iov->vf_device;
309cf0921beSKarimAllah Ahmed virtfn->is_virtfn = 1;
310cf0921beSKarimAllah Ahmed virtfn->physfn = pci_dev_get(dev);
31112856e7aSMatthew Rosato virtfn->no_command_memory = 1;
312cf0921beSKarimAllah Ahmed
313cf0921beSKarimAllah Ahmed if (id == 0)
314cf0921beSKarimAllah Ahmed pci_read_vf_config_common(virtfn);
315cf0921beSKarimAllah Ahmed
316156c5532SPo Liu rc = pci_setup_device(virtfn);
317156c5532SPo Liu if (rc)
318cf0921beSKarimAllah Ahmed goto failed1;
319156c5532SPo Liu
320dd7cc44dSYu Zhao virtfn->dev.parent = dev->dev.parent;
321aa931977SAlex Williamson virtfn->multifunction = 0;
322dd7cc44dSYu Zhao
323dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
324c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES];
325dd7cc44dSYu Zhao if (!res->parent)
326dd7cc44dSYu Zhao continue;
327dd7cc44dSYu Zhao virtfn->resource[i].name = pci_name(virtfn);
328dd7cc44dSYu Zhao virtfn->resource[i].flags = res->flags;
3290e6c9122SWei Yang size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
330dd7cc44dSYu Zhao virtfn->resource[i].start = res->start + size * id;
331dd7cc44dSYu Zhao virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
332dd7cc44dSYu Zhao rc = request_resource(res, &virtfn->resource[i]);
333dd7cc44dSYu Zhao BUG_ON(rc);
334dd7cc44dSYu Zhao }
335dd7cc44dSYu Zhao
336dd7cc44dSYu Zhao pci_device_add(virtfn, virtfn->bus);
337a1ceea67SNiklas Schnelle rc = pci_iov_sysfs_link(dev, virtfn, id);
338dd7cc44dSYu Zhao if (rc)
3398c386cc8SNavid Emamdoost goto failed1;
340dd7cc44dSYu Zhao
34127d61629SStuart Hayes pci_bus_add_device(virtfn);
34227d61629SStuart Hayes
343dd7cc44dSYu Zhao return 0;
344dd7cc44dSYu Zhao
345dd7cc44dSYu Zhao failed1:
3468c386cc8SNavid Emamdoost pci_stop_and_remove_bus_device(virtfn);
347dd7cc44dSYu Zhao pci_dev_put(dev);
348dc087f2fSJiang Liu failed0:
349dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, bus);
350dc087f2fSJiang Liu failed:
351dd7cc44dSYu Zhao
352dd7cc44dSYu Zhao return rc;
353dd7cc44dSYu Zhao }
354dd7cc44dSYu Zhao
pci_iov_remove_virtfn(struct pci_dev * dev,int id)355753f6124SJan H. Schönherr void pci_iov_remove_virtfn(struct pci_dev *dev, int id)
356dd7cc44dSYu Zhao {
357dd7cc44dSYu Zhao char buf[VIRTFN_ID_LEN];
358dd7cc44dSYu Zhao struct pci_dev *virtfn;
359dd7cc44dSYu Zhao
360dc087f2fSJiang Liu virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
361b07579c0SWei Yang pci_iov_virtfn_bus(dev, id),
362b07579c0SWei Yang pci_iov_virtfn_devfn(dev, id));
363dd7cc44dSYu Zhao if (!virtfn)
364dd7cc44dSYu Zhao return;
365dd7cc44dSYu Zhao
366dd7cc44dSYu Zhao sprintf(buf, "virtfn%u", id);
367dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, buf);
36809cedbefSYinghai Lu /*
36909cedbefSYinghai Lu * pci_stop_dev() could have been called for this virtfn already,
37009cedbefSYinghai Lu * so the directory for the virtfn may have been removed before.
37109cedbefSYinghai Lu * Double check to avoid spurious sysfs warnings.
37209cedbefSYinghai Lu */
37309cedbefSYinghai Lu if (virtfn->dev.kobj.sd)
374dd7cc44dSYu Zhao sysfs_remove_link(&virtfn->dev.kobj, "physfn");
375dd7cc44dSYu Zhao
376210647afSYinghai Lu pci_stop_and_remove_bus_device(virtfn);
377dc087f2fSJiang Liu virtfn_remove_bus(dev->bus, virtfn->bus);
378dd7cc44dSYu Zhao
379dc087f2fSJiang Liu /* balance pci_get_domain_bus_and_slot() */
380dc087f2fSJiang Liu pci_dev_put(virtfn);
381dd7cc44dSYu Zhao pci_dev_put(dev);
382dd7cc44dSYu Zhao }
383dd7cc44dSYu Zhao
sriov_totalvfs_show(struct device * dev,struct device_attribute * attr,char * buf)384aaee0c1fSKelsey Skunberg static ssize_t sriov_totalvfs_show(struct device *dev,
385aaee0c1fSKelsey Skunberg struct device_attribute *attr,
386aaee0c1fSKelsey Skunberg char *buf)
387aaee0c1fSKelsey Skunberg {
388aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
389aaee0c1fSKelsey Skunberg
390f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
391aaee0c1fSKelsey Skunberg }
392aaee0c1fSKelsey Skunberg
sriov_numvfs_show(struct device * dev,struct device_attribute * attr,char * buf)393aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_show(struct device *dev,
394aaee0c1fSKelsey Skunberg struct device_attribute *attr,
395aaee0c1fSKelsey Skunberg char *buf)
396aaee0c1fSKelsey Skunberg {
397aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
39835ff867bSPierre Crégut u16 num_vfs;
399aaee0c1fSKelsey Skunberg
40035ff867bSPierre Crégut /* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */
40135ff867bSPierre Crégut device_lock(&pdev->dev);
40235ff867bSPierre Crégut num_vfs = pdev->sriov->num_VFs;
40335ff867bSPierre Crégut device_unlock(&pdev->dev);
40435ff867bSPierre Crégut
405f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", num_vfs);
406aaee0c1fSKelsey Skunberg }
407aaee0c1fSKelsey Skunberg
408aaee0c1fSKelsey Skunberg /*
409aaee0c1fSKelsey Skunberg * num_vfs > 0; number of VFs to enable
410aaee0c1fSKelsey Skunberg * num_vfs = 0; disable all VFs
411aaee0c1fSKelsey Skunberg *
412aaee0c1fSKelsey Skunberg * Note: SRIOV spec does not allow partial VF
413aaee0c1fSKelsey Skunberg * disable, so it's all or none.
414aaee0c1fSKelsey Skunberg */
sriov_numvfs_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)415aaee0c1fSKelsey Skunberg static ssize_t sriov_numvfs_store(struct device *dev,
416aaee0c1fSKelsey Skunberg struct device_attribute *attr,
417aaee0c1fSKelsey Skunberg const char *buf, size_t count)
418aaee0c1fSKelsey Skunberg {
419aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
42036f354ecSKrzysztof Wilczyński int ret = 0;
421aaee0c1fSKelsey Skunberg u16 num_vfs;
422aaee0c1fSKelsey Skunberg
42336f354ecSKrzysztof Wilczyński if (kstrtou16(buf, 0, &num_vfs) < 0)
42436f354ecSKrzysztof Wilczyński return -EINVAL;
425aaee0c1fSKelsey Skunberg
426aaee0c1fSKelsey Skunberg if (num_vfs > pci_sriov_get_totalvfs(pdev))
427aaee0c1fSKelsey Skunberg return -ERANGE;
428aaee0c1fSKelsey Skunberg
429aaee0c1fSKelsey Skunberg device_lock(&pdev->dev);
430aaee0c1fSKelsey Skunberg
431aaee0c1fSKelsey Skunberg if (num_vfs == pdev->sriov->num_VFs)
432aaee0c1fSKelsey Skunberg goto exit;
433aaee0c1fSKelsey Skunberg
434e9c3bbd6SMoritz Fischer /* is PF driver loaded */
435e0217c5bSBjorn Helgaas if (!pdev->driver) {
436e9c3bbd6SMoritz Fischer pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n");
437e9c3bbd6SMoritz Fischer ret = -ENOENT;
438e9c3bbd6SMoritz Fischer goto exit;
439e9c3bbd6SMoritz Fischer }
440e9c3bbd6SMoritz Fischer
441aaee0c1fSKelsey Skunberg /* is PF driver loaded w/callback */
442e0217c5bSBjorn Helgaas if (!pdev->driver->sriov_configure) {
443e9c3bbd6SMoritz Fischer pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n");
444aaee0c1fSKelsey Skunberg ret = -ENOENT;
445aaee0c1fSKelsey Skunberg goto exit;
446aaee0c1fSKelsey Skunberg }
447aaee0c1fSKelsey Skunberg
448aaee0c1fSKelsey Skunberg if (num_vfs == 0) {
449aaee0c1fSKelsey Skunberg /* disable VFs */
450e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_configure(pdev, 0);
451aaee0c1fSKelsey Skunberg goto exit;
452aaee0c1fSKelsey Skunberg }
453aaee0c1fSKelsey Skunberg
454aaee0c1fSKelsey Skunberg /* enable VFs */
455aaee0c1fSKelsey Skunberg if (pdev->sriov->num_VFs) {
456aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n",
457aaee0c1fSKelsey Skunberg pdev->sriov->num_VFs, num_vfs);
458aaee0c1fSKelsey Skunberg ret = -EBUSY;
459aaee0c1fSKelsey Skunberg goto exit;
460aaee0c1fSKelsey Skunberg }
461aaee0c1fSKelsey Skunberg
462e0217c5bSBjorn Helgaas ret = pdev->driver->sriov_configure(pdev, num_vfs);
463aaee0c1fSKelsey Skunberg if (ret < 0)
464aaee0c1fSKelsey Skunberg goto exit;
465aaee0c1fSKelsey Skunberg
466aaee0c1fSKelsey Skunberg if (ret != num_vfs)
467aaee0c1fSKelsey Skunberg pci_warn(pdev, "%d VFs requested; only %d enabled\n",
468aaee0c1fSKelsey Skunberg num_vfs, ret);
469aaee0c1fSKelsey Skunberg
470aaee0c1fSKelsey Skunberg exit:
471aaee0c1fSKelsey Skunberg device_unlock(&pdev->dev);
472aaee0c1fSKelsey Skunberg
473aaee0c1fSKelsey Skunberg if (ret < 0)
474aaee0c1fSKelsey Skunberg return ret;
475aaee0c1fSKelsey Skunberg
476aaee0c1fSKelsey Skunberg return count;
477aaee0c1fSKelsey Skunberg }
478aaee0c1fSKelsey Skunberg
sriov_offset_show(struct device * dev,struct device_attribute * attr,char * buf)479aaee0c1fSKelsey Skunberg static ssize_t sriov_offset_show(struct device *dev,
480aaee0c1fSKelsey Skunberg struct device_attribute *attr,
481aaee0c1fSKelsey Skunberg char *buf)
482aaee0c1fSKelsey Skunberg {
483aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
484aaee0c1fSKelsey Skunberg
485f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->offset);
486aaee0c1fSKelsey Skunberg }
487aaee0c1fSKelsey Skunberg
sriov_stride_show(struct device * dev,struct device_attribute * attr,char * buf)488aaee0c1fSKelsey Skunberg static ssize_t sriov_stride_show(struct device *dev,
489aaee0c1fSKelsey Skunberg struct device_attribute *attr,
490aaee0c1fSKelsey Skunberg char *buf)
491aaee0c1fSKelsey Skunberg {
492aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
493aaee0c1fSKelsey Skunberg
494f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->stride);
495aaee0c1fSKelsey Skunberg }
496aaee0c1fSKelsey Skunberg
sriov_vf_device_show(struct device * dev,struct device_attribute * attr,char * buf)497aaee0c1fSKelsey Skunberg static ssize_t sriov_vf_device_show(struct device *dev,
498aaee0c1fSKelsey Skunberg struct device_attribute *attr,
499aaee0c1fSKelsey Skunberg char *buf)
500aaee0c1fSKelsey Skunberg {
501aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
502aaee0c1fSKelsey Skunberg
503f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device);
504aaee0c1fSKelsey Skunberg }
505aaee0c1fSKelsey Skunberg
sriov_drivers_autoprobe_show(struct device * dev,struct device_attribute * attr,char * buf)506aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
507aaee0c1fSKelsey Skunberg struct device_attribute *attr,
508aaee0c1fSKelsey Skunberg char *buf)
509aaee0c1fSKelsey Skunberg {
510aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
511aaee0c1fSKelsey Skunberg
512f8cf6e51SKrzysztof Wilczyński return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe);
513aaee0c1fSKelsey Skunberg }
514aaee0c1fSKelsey Skunberg
sriov_drivers_autoprobe_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)515aaee0c1fSKelsey Skunberg static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
516aaee0c1fSKelsey Skunberg struct device_attribute *attr,
517aaee0c1fSKelsey Skunberg const char *buf, size_t count)
518aaee0c1fSKelsey Skunberg {
519aaee0c1fSKelsey Skunberg struct pci_dev *pdev = to_pci_dev(dev);
520aaee0c1fSKelsey Skunberg bool drivers_autoprobe;
521aaee0c1fSKelsey Skunberg
522aaee0c1fSKelsey Skunberg if (kstrtobool(buf, &drivers_autoprobe) < 0)
523aaee0c1fSKelsey Skunberg return -EINVAL;
524aaee0c1fSKelsey Skunberg
525aaee0c1fSKelsey Skunberg pdev->sriov->drivers_autoprobe = drivers_autoprobe;
526aaee0c1fSKelsey Skunberg
527aaee0c1fSKelsey Skunberg return count;
528aaee0c1fSKelsey Skunberg }
529aaee0c1fSKelsey Skunberg
530aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_totalvfs);
531244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_numvfs);
532aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_offset);
533aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_stride);
534aaee0c1fSKelsey Skunberg static DEVICE_ATTR_RO(sriov_vf_device);
535244c06c3SKelsey Skunberg static DEVICE_ATTR_RW(sriov_drivers_autoprobe);
536aaee0c1fSKelsey Skunberg
537c3d5c2d9SLeon Romanovsky static struct attribute *sriov_pf_dev_attrs[] = {
538aaee0c1fSKelsey Skunberg &dev_attr_sriov_totalvfs.attr,
539aaee0c1fSKelsey Skunberg &dev_attr_sriov_numvfs.attr,
540aaee0c1fSKelsey Skunberg &dev_attr_sriov_offset.attr,
541aaee0c1fSKelsey Skunberg &dev_attr_sriov_stride.attr,
542aaee0c1fSKelsey Skunberg &dev_attr_sriov_vf_device.attr,
543aaee0c1fSKelsey Skunberg &dev_attr_sriov_drivers_autoprobe.attr,
544c3d5c2d9SLeon Romanovsky #ifdef CONFIG_PCI_MSI
545c3d5c2d9SLeon Romanovsky &dev_attr_sriov_vf_total_msix.attr,
546c3d5c2d9SLeon Romanovsky #endif
547aaee0c1fSKelsey Skunberg NULL,
548aaee0c1fSKelsey Skunberg };
549aaee0c1fSKelsey Skunberg
sriov_pf_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)550c3d5c2d9SLeon Romanovsky static umode_t sriov_pf_attrs_are_visible(struct kobject *kobj,
551aaee0c1fSKelsey Skunberg struct attribute *a, int n)
552aaee0c1fSKelsey Skunberg {
553aaee0c1fSKelsey Skunberg struct device *dev = kobj_to_dev(kobj);
554aaee0c1fSKelsey Skunberg
555aaee0c1fSKelsey Skunberg if (!dev_is_pf(dev))
556aaee0c1fSKelsey Skunberg return 0;
557aaee0c1fSKelsey Skunberg
558aaee0c1fSKelsey Skunberg return a->mode;
559aaee0c1fSKelsey Skunberg }
560aaee0c1fSKelsey Skunberg
561c3d5c2d9SLeon Romanovsky const struct attribute_group sriov_pf_dev_attr_group = {
562c3d5c2d9SLeon Romanovsky .attrs = sriov_pf_dev_attrs,
563c3d5c2d9SLeon Romanovsky .is_visible = sriov_pf_attrs_are_visible,
564aaee0c1fSKelsey Skunberg };
565aaee0c1fSKelsey Skunberg
pcibios_sriov_enable(struct pci_dev * pdev,u16 num_vfs)566995df527SWei Yang int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
567995df527SWei Yang {
568995df527SWei Yang return 0;
569995df527SWei Yang }
570995df527SWei Yang
pcibios_sriov_disable(struct pci_dev * pdev)571a39e3fcdSAlexander Duyck int __weak pcibios_sriov_disable(struct pci_dev *pdev)
572a39e3fcdSAlexander Duyck {
573a39e3fcdSAlexander Duyck return 0;
574a39e3fcdSAlexander Duyck }
575a39e3fcdSAlexander Duyck
sriov_add_vfs(struct pci_dev * dev,u16 num_vfs)57618f9e9d1SSebastian Ott static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs)
57718f9e9d1SSebastian Ott {
57818f9e9d1SSebastian Ott unsigned int i;
57918f9e9d1SSebastian Ott int rc;
58018f9e9d1SSebastian Ott
581aff68a5aSSebastian Ott if (dev->no_vf_scan)
582aff68a5aSSebastian Ott return 0;
583aff68a5aSSebastian Ott
58418f9e9d1SSebastian Ott for (i = 0; i < num_vfs; i++) {
58518f9e9d1SSebastian Ott rc = pci_iov_add_virtfn(dev, i);
58618f9e9d1SSebastian Ott if (rc)
58718f9e9d1SSebastian Ott goto failed;
58818f9e9d1SSebastian Ott }
58918f9e9d1SSebastian Ott return 0;
59018f9e9d1SSebastian Ott failed:
59118f9e9d1SSebastian Ott while (i--)
59218f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i);
59318f9e9d1SSebastian Ott
59418f9e9d1SSebastian Ott return rc;
59518f9e9d1SSebastian Ott }
59618f9e9d1SSebastian Ott
sriov_enable(struct pci_dev * dev,int nr_virtfn)597dd7cc44dSYu Zhao static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
598dd7cc44dSYu Zhao {
599dd7cc44dSYu Zhao int rc;
6003443c382SAlexander Duyck int i;
601dd7cc44dSYu Zhao int nres;
602ce288ec3SAlexander Duyck u16 initial;
603dd7cc44dSYu Zhao struct resource *res;
604dd7cc44dSYu Zhao struct pci_dev *pdev;
605dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov;
606bbef98abSRam Pai int bars = 0;
607b07579c0SWei Yang int bus;
608dd7cc44dSYu Zhao
609dd7cc44dSYu Zhao if (!nr_virtfn)
610dd7cc44dSYu Zhao return 0;
611dd7cc44dSYu Zhao
6126b136724SBjorn Helgaas if (iov->num_VFs)
613dd7cc44dSYu Zhao return -EINVAL;
614dd7cc44dSYu Zhao
615dd7cc44dSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
6166b136724SBjorn Helgaas if (initial > iov->total_VFs ||
6176b136724SBjorn Helgaas (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs)))
618dd7cc44dSYu Zhao return -EIO;
619dd7cc44dSYu Zhao
6206b136724SBjorn Helgaas if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs ||
621dd7cc44dSYu Zhao (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
622dd7cc44dSYu Zhao return -EINVAL;
623dd7cc44dSYu Zhao
624dd7cc44dSYu Zhao nres = 0;
625dd7cc44dSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
626bbef98abSRam Pai bars |= (1 << (i + PCI_IOV_RESOURCES));
627c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES];
628dd7cc44dSYu Zhao if (res->parent)
629dd7cc44dSYu Zhao nres++;
630dd7cc44dSYu Zhao }
631dd7cc44dSYu Zhao if (nres != iov->nres) {
6327506dc79SFrederick Lawler pci_err(dev, "not enough MMIO resources for SR-IOV\n");
633dd7cc44dSYu Zhao return -ENOMEM;
634dd7cc44dSYu Zhao }
635dd7cc44dSYu Zhao
636b07579c0SWei Yang bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1);
63768f8e9faSBjorn Helgaas if (bus > dev->bus->busn_res.end) {
6387506dc79SFrederick Lawler pci_err(dev, "can't enable %d VFs (bus %02x out of range of %pR)\n",
63968f8e9faSBjorn Helgaas nr_virtfn, bus, &dev->bus->busn_res);
640dd7cc44dSYu Zhao return -ENOMEM;
641dd7cc44dSYu Zhao }
642dd7cc44dSYu Zhao
643bbef98abSRam Pai if (pci_enable_resources(dev, bars)) {
6447506dc79SFrederick Lawler pci_err(dev, "SR-IOV: IOV BARS not allocated\n");
645bbef98abSRam Pai return -ENOMEM;
646bbef98abSRam Pai }
647bbef98abSRam Pai
648dd7cc44dSYu Zhao if (iov->link != dev->devfn) {
649dd7cc44dSYu Zhao pdev = pci_get_slot(dev->bus, iov->link);
650dd7cc44dSYu Zhao if (!pdev)
651dd7cc44dSYu Zhao return -ENODEV;
652dd7cc44dSYu Zhao
653dc087f2fSJiang Liu if (!pdev->is_physfn) {
654dd7cc44dSYu Zhao pci_dev_put(pdev);
655652d1100SStefan Assmann return -ENOSYS;
656dc087f2fSJiang Liu }
657dd7cc44dSYu Zhao
658dd7cc44dSYu Zhao rc = sysfs_create_link(&dev->dev.kobj,
659dd7cc44dSYu Zhao &pdev->dev.kobj, "dep_link");
660dc087f2fSJiang Liu pci_dev_put(pdev);
661dd7cc44dSYu Zhao if (rc)
662dd7cc44dSYu Zhao return rc;
663dd7cc44dSYu Zhao }
664dd7cc44dSYu Zhao
6656b136724SBjorn Helgaas iov->initial_VFs = initial;
666dd7cc44dSYu Zhao if (nr_virtfn < initial)
667dd7cc44dSYu Zhao initial = nr_virtfn;
668dd7cc44dSYu Zhao
669c23b6135SAlexander Duyck rc = pcibios_sriov_enable(dev, initial);
670c23b6135SAlexander Duyck if (rc) {
6717506dc79SFrederick Lawler pci_err(dev, "failure %d from pcibios_sriov_enable()\n", rc);
672c23b6135SAlexander Duyck goto err_pcibios;
673995df527SWei Yang }
674995df527SWei Yang
675f40ec3c7SGavin Shan pci_iov_set_numvfs(dev, nr_virtfn);
676f40ec3c7SGavin Shan iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
677f40ec3c7SGavin Shan pci_cfg_access_lock(dev);
678f40ec3c7SGavin Shan pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
679f40ec3c7SGavin Shan msleep(100);
680f40ec3c7SGavin Shan pci_cfg_access_unlock(dev);
681f40ec3c7SGavin Shan
68218f9e9d1SSebastian Ott rc = sriov_add_vfs(dev, initial);
683dd7cc44dSYu Zhao if (rc)
68418f9e9d1SSebastian Ott goto err_pcibios;
685dd7cc44dSYu Zhao
686dd7cc44dSYu Zhao kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
6876b136724SBjorn Helgaas iov->num_VFs = nr_virtfn;
688dd7cc44dSYu Zhao
689dd7cc44dSYu Zhao return 0;
690dd7cc44dSYu Zhao
691c23b6135SAlexander Duyck err_pcibios:
692dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
693fb51ccbfSJan Kiszka pci_cfg_access_lock(dev);
694dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
695dd7cc44dSYu Zhao ssleep(1);
696fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev);
697dd7cc44dSYu Zhao
6980fc690a7SGavin Shan pcibios_sriov_disable(dev);
6990fc690a7SGavin Shan
700dd7cc44dSYu Zhao if (iov->link != dev->devfn)
701dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link");
702dd7cc44dSYu Zhao
703b3908644SAlexander Duyck pci_iov_set_numvfs(dev, 0);
704dd7cc44dSYu Zhao return rc;
705dd7cc44dSYu Zhao }
706dd7cc44dSYu Zhao
sriov_del_vfs(struct pci_dev * dev)70718f9e9d1SSebastian Ott static void sriov_del_vfs(struct pci_dev *dev)
70818f9e9d1SSebastian Ott {
70918f9e9d1SSebastian Ott struct pci_sriov *iov = dev->sriov;
71018f9e9d1SSebastian Ott int i;
71118f9e9d1SSebastian Ott
71218f9e9d1SSebastian Ott for (i = 0; i < iov->num_VFs; i++)
71318f9e9d1SSebastian Ott pci_iov_remove_virtfn(dev, i);
71418f9e9d1SSebastian Ott }
71518f9e9d1SSebastian Ott
sriov_disable(struct pci_dev * dev)716dd7cc44dSYu Zhao static void sriov_disable(struct pci_dev *dev)
717dd7cc44dSYu Zhao {
718dd7cc44dSYu Zhao struct pci_sriov *iov = dev->sriov;
719dd7cc44dSYu Zhao
7206b136724SBjorn Helgaas if (!iov->num_VFs)
721dd7cc44dSYu Zhao return;
722dd7cc44dSYu Zhao
72318f9e9d1SSebastian Ott sriov_del_vfs(dev);
724dd7cc44dSYu Zhao iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
725fb51ccbfSJan Kiszka pci_cfg_access_lock(dev);
726dd7cc44dSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
727dd7cc44dSYu Zhao ssleep(1);
728fb51ccbfSJan Kiszka pci_cfg_access_unlock(dev);
729dd7cc44dSYu Zhao
7300fc690a7SGavin Shan pcibios_sriov_disable(dev);
7310fc690a7SGavin Shan
732dd7cc44dSYu Zhao if (iov->link != dev->devfn)
733dd7cc44dSYu Zhao sysfs_remove_link(&dev->dev.kobj, "dep_link");
734dd7cc44dSYu Zhao
7356b136724SBjorn Helgaas iov->num_VFs = 0;
736f59dca27SWei Yang pci_iov_set_numvfs(dev, 0);
737dd7cc44dSYu Zhao }
738dd7cc44dSYu Zhao
sriov_init(struct pci_dev * dev,int pos)739d1b054daSYu Zhao static int sriov_init(struct pci_dev *dev, int pos)
740d1b054daSYu Zhao {
7410e6c9122SWei Yang int i, bar64;
742d1b054daSYu Zhao int rc;
743d1b054daSYu Zhao int nres;
744d1b054daSYu Zhao u32 pgsz;
745ea9a8854SAlexander Duyck u16 ctrl, total;
746d1b054daSYu Zhao struct pci_sriov *iov;
747d1b054daSYu Zhao struct resource *res;
748*dc4e6f21SPuranjay Mohan const char *res_name;
749d1b054daSYu Zhao struct pci_dev *pdev;
750d1b054daSYu Zhao
751d1b054daSYu Zhao pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
752d1b054daSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE) {
753d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
754d1b054daSYu Zhao ssleep(1);
755d1b054daSYu Zhao }
756d1b054daSYu Zhao
757d1b054daSYu Zhao ctrl = 0;
758d1b054daSYu Zhao list_for_each_entry(pdev, &dev->bus->devices, bus_list)
759d1b054daSYu Zhao if (pdev->is_physfn)
760d1b054daSYu Zhao goto found;
761d1b054daSYu Zhao
762d1b054daSYu Zhao pdev = NULL;
763d1b054daSYu Zhao if (pci_ari_enabled(dev->bus))
764d1b054daSYu Zhao ctrl |= PCI_SRIOV_CTRL_ARI;
765d1b054daSYu Zhao
766d1b054daSYu Zhao found:
767d1b054daSYu Zhao pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
768d1b054daSYu Zhao
769ff45f9ddSBen Shelton pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total);
770ff45f9ddSBen Shelton if (!total)
771ff45f9ddSBen Shelton return 0;
772d1b054daSYu Zhao
773d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz);
774d1b054daSYu Zhao i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0;
775d1b054daSYu Zhao pgsz &= ~((1 << i) - 1);
776d1b054daSYu Zhao if (!pgsz)
777d1b054daSYu Zhao return -EIO;
778d1b054daSYu Zhao
779d1b054daSYu Zhao pgsz &= ~(pgsz - 1);
7808161fe91SVaidyanathan Srinivasan pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
781d1b054daSYu Zhao
7820e6c9122SWei Yang iov = kzalloc(sizeof(*iov), GFP_KERNEL);
7830e6c9122SWei Yang if (!iov)
7840e6c9122SWei Yang return -ENOMEM;
7850e6c9122SWei Yang
786d1b054daSYu Zhao nres = 0;
787d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
788c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES];
789*dc4e6f21SPuranjay Mohan res_name = pci_resource_name(dev, i + PCI_IOV_RESOURCES);
790*dc4e6f21SPuranjay Mohan
79111183991SDavid Daney /*
79211183991SDavid Daney * If it is already FIXED, don't change it, something
79311183991SDavid Daney * (perhaps EA or header fixups) wants it this way.
79411183991SDavid Daney */
79511183991SDavid Daney if (res->flags & IORESOURCE_PCI_FIXED)
79611183991SDavid Daney bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
79711183991SDavid Daney else
7980e6c9122SWei Yang bar64 = __pci_read_base(dev, pci_bar_unknown, res,
799d1b054daSYu Zhao pos + PCI_SRIOV_BAR + i * 4);
800d1b054daSYu Zhao if (!res->flags)
801d1b054daSYu Zhao continue;
802d1b054daSYu Zhao if (resource_size(res) & (PAGE_SIZE - 1)) {
803d1b054daSYu Zhao rc = -EIO;
804d1b054daSYu Zhao goto failed;
805d1b054daSYu Zhao }
8060e6c9122SWei Yang iov->barsz[i] = resource_size(res);
807d1b054daSYu Zhao res->end = res->start + resource_size(res) * total - 1;
808*dc4e6f21SPuranjay Mohan pci_info(dev, "%s %pR: contains BAR %d for %d VFs\n",
809*dc4e6f21SPuranjay Mohan res_name, res, i, total);
8100e6c9122SWei Yang i += bar64;
811d1b054daSYu Zhao nres++;
812d1b054daSYu Zhao }
813d1b054daSYu Zhao
814d1b054daSYu Zhao iov->pos = pos;
815d1b054daSYu Zhao iov->nres = nres;
816d1b054daSYu Zhao iov->ctrl = ctrl;
8176b136724SBjorn Helgaas iov->total_VFs = total;
8188d85a7a4SJakub Kicinski iov->driver_max_VFs = total;
8193142d832SFilippo Sironi pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device);
820d1b054daSYu Zhao iov->pgsz = pgsz;
821d1b054daSYu Zhao iov->self = dev;
8220e7df224SBodong Wang iov->drivers_autoprobe = true;
823d1b054daSYu Zhao pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
824d1b054daSYu Zhao pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
82562f87c0eSYijing Wang if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
8264d135dbeSYu Zhao iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
827d1b054daSYu Zhao
828d1b054daSYu Zhao if (pdev)
829d1b054daSYu Zhao iov->dev = pci_dev_get(pdev);
830e277d2fcSYu Zhao else
831d1b054daSYu Zhao iov->dev = dev;
832e277d2fcSYu Zhao
833d1b054daSYu Zhao dev->sriov = iov;
834d1b054daSYu Zhao dev->is_physfn = 1;
835ea9a8854SAlexander Duyck rc = compute_max_vf_buses(dev);
836ea9a8854SAlexander Duyck if (rc)
837ea9a8854SAlexander Duyck goto fail_max_buses;
838d1b054daSYu Zhao
839d1b054daSYu Zhao return 0;
840d1b054daSYu Zhao
841ea9a8854SAlexander Duyck fail_max_buses:
842ea9a8854SAlexander Duyck dev->sriov = NULL;
843ea9a8854SAlexander Duyck dev->is_physfn = 0;
844d1b054daSYu Zhao failed:
845d1b054daSYu Zhao for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
846c1fe1f96SBjorn Helgaas res = &dev->resource[i + PCI_IOV_RESOURCES];
847d1b054daSYu Zhao res->flags = 0;
848d1b054daSYu Zhao }
849d1b054daSYu Zhao
8500e6c9122SWei Yang kfree(iov);
851d1b054daSYu Zhao return rc;
852d1b054daSYu Zhao }
853d1b054daSYu Zhao
sriov_release(struct pci_dev * dev)854d1b054daSYu Zhao static void sriov_release(struct pci_dev *dev)
855d1b054daSYu Zhao {
8566b136724SBjorn Helgaas BUG_ON(dev->sriov->num_VFs);
857dd7cc44dSYu Zhao
858e277d2fcSYu Zhao if (dev != dev->sriov->dev)
859d1b054daSYu Zhao pci_dev_put(dev->sriov->dev);
860d1b054daSYu Zhao
861d1b054daSYu Zhao kfree(dev->sriov);
862d1b054daSYu Zhao dev->sriov = NULL;
863d1b054daSYu Zhao }
864d1b054daSYu Zhao
sriov_restore_state(struct pci_dev * dev)8658c5cdb6aSYu Zhao static void sriov_restore_state(struct pci_dev *dev)
8668c5cdb6aSYu Zhao {
8678c5cdb6aSYu Zhao int i;
8688c5cdb6aSYu Zhao u16 ctrl;
8698c5cdb6aSYu Zhao struct pci_sriov *iov = dev->sriov;
8708c5cdb6aSYu Zhao
8718c5cdb6aSYu Zhao pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl);
8728c5cdb6aSYu Zhao if (ctrl & PCI_SRIOV_CTRL_VFE)
8738c5cdb6aSYu Zhao return;
8748c5cdb6aSYu Zhao
875ff26449eSTony Nguyen /*
876ff26449eSTony Nguyen * Restore PCI_SRIOV_CTRL_ARI before pci_iov_set_numvfs() because
877ff26449eSTony Nguyen * it reads offset & stride, which depend on PCI_SRIOV_CTRL_ARI.
878ff26449eSTony Nguyen */
879ff26449eSTony Nguyen ctrl &= ~PCI_SRIOV_CTRL_ARI;
880ff26449eSTony Nguyen ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI;
881ff26449eSTony Nguyen pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
882ff26449eSTony Nguyen
88339098edbSDenis Efremov for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
88439098edbSDenis Efremov pci_update_resource(dev, i + PCI_IOV_RESOURCES);
8858c5cdb6aSYu Zhao
8868c5cdb6aSYu Zhao pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
887f59dca27SWei Yang pci_iov_set_numvfs(dev, iov->num_VFs);
8888c5cdb6aSYu Zhao pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
8898c5cdb6aSYu Zhao if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
8908c5cdb6aSYu Zhao msleep(100);
8918c5cdb6aSYu Zhao }
8928c5cdb6aSYu Zhao
893d1b054daSYu Zhao /**
894d1b054daSYu Zhao * pci_iov_init - initialize the IOV capability
895d1b054daSYu Zhao * @dev: the PCI device
896d1b054daSYu Zhao *
897d1b054daSYu Zhao * Returns 0 on success, or negative on failure.
898d1b054daSYu Zhao */
pci_iov_init(struct pci_dev * dev)899d1b054daSYu Zhao int pci_iov_init(struct pci_dev *dev)
900d1b054daSYu Zhao {
901d1b054daSYu Zhao int pos;
902d1b054daSYu Zhao
9035f4d91a1SKenji Kaneshige if (!pci_is_pcie(dev))
904d1b054daSYu Zhao return -ENODEV;
905d1b054daSYu Zhao
906d1b054daSYu Zhao pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
907d1b054daSYu Zhao if (pos)
908d1b054daSYu Zhao return sriov_init(dev, pos);
909d1b054daSYu Zhao
910d1b054daSYu Zhao return -ENODEV;
911d1b054daSYu Zhao }
912d1b054daSYu Zhao
913d1b054daSYu Zhao /**
914d1b054daSYu Zhao * pci_iov_release - release resources used by the IOV capability
915d1b054daSYu Zhao * @dev: the PCI device
916d1b054daSYu Zhao */
pci_iov_release(struct pci_dev * dev)917d1b054daSYu Zhao void pci_iov_release(struct pci_dev *dev)
918d1b054daSYu Zhao {
919d1b054daSYu Zhao if (dev->is_physfn)
920d1b054daSYu Zhao sriov_release(dev);
921d1b054daSYu Zhao }
922d1b054daSYu Zhao
923d1b054daSYu Zhao /**
92438972375SJakub Kicinski * pci_iov_remove - clean up SR-IOV state after PF driver is detached
92538972375SJakub Kicinski * @dev: the PCI device
92638972375SJakub Kicinski */
pci_iov_remove(struct pci_dev * dev)92738972375SJakub Kicinski void pci_iov_remove(struct pci_dev *dev)
92838972375SJakub Kicinski {
92938972375SJakub Kicinski struct pci_sriov *iov = dev->sriov;
93038972375SJakub Kicinski
93138972375SJakub Kicinski if (!dev->is_physfn)
93238972375SJakub Kicinski return;
93338972375SJakub Kicinski
93438972375SJakub Kicinski iov->driver_max_VFs = iov->total_VFs;
93538972375SJakub Kicinski if (iov->num_VFs)
93638972375SJakub Kicinski pci_warn(dev, "driver left SR-IOV enabled after remove\n");
93738972375SJakub Kicinski }
93838972375SJakub Kicinski
93938972375SJakub Kicinski /**
9406ffa2489SBjorn Helgaas * pci_iov_update_resource - update a VF BAR
9416ffa2489SBjorn Helgaas * @dev: the PCI device
9426ffa2489SBjorn Helgaas * @resno: the resource number
9436ffa2489SBjorn Helgaas *
9446ffa2489SBjorn Helgaas * Update a VF BAR in the SR-IOV capability of a PF.
9456ffa2489SBjorn Helgaas */
pci_iov_update_resource(struct pci_dev * dev,int resno)9466ffa2489SBjorn Helgaas void pci_iov_update_resource(struct pci_dev *dev, int resno)
9476ffa2489SBjorn Helgaas {
9486ffa2489SBjorn Helgaas struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
9496ffa2489SBjorn Helgaas struct resource *res = dev->resource + resno;
9506ffa2489SBjorn Helgaas int vf_bar = resno - PCI_IOV_RESOURCES;
9516ffa2489SBjorn Helgaas struct pci_bus_region region;
952546ba9f8SBjorn Helgaas u16 cmd;
9536ffa2489SBjorn Helgaas u32 new;
9546ffa2489SBjorn Helgaas int reg;
9556ffa2489SBjorn Helgaas
9566ffa2489SBjorn Helgaas /*
9576ffa2489SBjorn Helgaas * The generic pci_restore_bars() path calls this for all devices,
9586ffa2489SBjorn Helgaas * including VFs and non-SR-IOV devices. If this is not a PF, we
9596ffa2489SBjorn Helgaas * have nothing to do.
9606ffa2489SBjorn Helgaas */
9616ffa2489SBjorn Helgaas if (!iov)
9626ffa2489SBjorn Helgaas return;
9636ffa2489SBjorn Helgaas
964546ba9f8SBjorn Helgaas pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd);
965546ba9f8SBjorn Helgaas if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) {
966546ba9f8SBjorn Helgaas dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n",
967546ba9f8SBjorn Helgaas vf_bar, res);
968546ba9f8SBjorn Helgaas return;
969546ba9f8SBjorn Helgaas }
970546ba9f8SBjorn Helgaas
9716ffa2489SBjorn Helgaas /*
9726ffa2489SBjorn Helgaas * Ignore unimplemented BARs, unused resource slots for 64-bit
9736ffa2489SBjorn Helgaas * BARs, and non-movable resources, e.g., those described via
9746ffa2489SBjorn Helgaas * Enhanced Allocation.
9756ffa2489SBjorn Helgaas */
9766ffa2489SBjorn Helgaas if (!res->flags)
9776ffa2489SBjorn Helgaas return;
9786ffa2489SBjorn Helgaas
9796ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_UNSET)
9806ffa2489SBjorn Helgaas return;
9816ffa2489SBjorn Helgaas
9826ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_PCI_FIXED)
9836ffa2489SBjorn Helgaas return;
9846ffa2489SBjorn Helgaas
9856ffa2489SBjorn Helgaas pcibios_resource_to_bus(dev->bus, ®ion, res);
9866ffa2489SBjorn Helgaas new = region.start;
9876ffa2489SBjorn Helgaas new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
9886ffa2489SBjorn Helgaas
9896ffa2489SBjorn Helgaas reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar;
9906ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg, new);
9916ffa2489SBjorn Helgaas if (res->flags & IORESOURCE_MEM_64) {
9926ffa2489SBjorn Helgaas new = region.start >> 16 >> 16;
9936ffa2489SBjorn Helgaas pci_write_config_dword(dev, reg + 4, new);
9946ffa2489SBjorn Helgaas }
9956ffa2489SBjorn Helgaas }
9966ffa2489SBjorn Helgaas
pcibios_iov_resource_alignment(struct pci_dev * dev,int resno)997978d2d68SWei Yang resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev,
998978d2d68SWei Yang int resno)
999978d2d68SWei Yang {
1000978d2d68SWei Yang return pci_iov_resource_size(dev, resno);
1001978d2d68SWei Yang }
1002978d2d68SWei Yang
10038c5cdb6aSYu Zhao /**
10046faf17f6SChris Wright * pci_sriov_resource_alignment - get resource alignment for VF BAR
10056faf17f6SChris Wright * @dev: the PCI device
10066faf17f6SChris Wright * @resno: the resource number
10076faf17f6SChris Wright *
10086faf17f6SChris Wright * Returns the alignment of the VF BAR found in the SR-IOV capability.
10096faf17f6SChris Wright * This is not the same as the resource size which is defined as
10106faf17f6SChris Wright * the VF BAR size multiplied by the number of VFs. The alignment
10116faf17f6SChris Wright * is just the VF BAR size.
10126faf17f6SChris Wright */
pci_sriov_resource_alignment(struct pci_dev * dev,int resno)10130e52247aSCam Macdonell resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
10146faf17f6SChris Wright {
1015978d2d68SWei Yang return pcibios_iov_resource_alignment(dev, resno);
10166faf17f6SChris Wright }
10176faf17f6SChris Wright
10186faf17f6SChris Wright /**
10198c5cdb6aSYu Zhao * pci_restore_iov_state - restore the state of the IOV capability
10208c5cdb6aSYu Zhao * @dev: the PCI device
10218c5cdb6aSYu Zhao */
pci_restore_iov_state(struct pci_dev * dev)10228c5cdb6aSYu Zhao void pci_restore_iov_state(struct pci_dev *dev)
10238c5cdb6aSYu Zhao {
10248c5cdb6aSYu Zhao if (dev->is_physfn)
10258c5cdb6aSYu Zhao sriov_restore_state(dev);
10268c5cdb6aSYu Zhao }
1027a28724b0SYu Zhao
1028a28724b0SYu Zhao /**
1029608c0d88SBryant G. Ly * pci_vf_drivers_autoprobe - set PF property drivers_autoprobe for VFs
1030608c0d88SBryant G. Ly * @dev: the PCI device
1031608c0d88SBryant G. Ly * @auto_probe: set VF drivers auto probe flag
1032608c0d88SBryant G. Ly */
pci_vf_drivers_autoprobe(struct pci_dev * dev,bool auto_probe)1033608c0d88SBryant G. Ly void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool auto_probe)
1034608c0d88SBryant G. Ly {
1035608c0d88SBryant G. Ly if (dev->is_physfn)
1036608c0d88SBryant G. Ly dev->sriov->drivers_autoprobe = auto_probe;
1037608c0d88SBryant G. Ly }
1038608c0d88SBryant G. Ly
1039608c0d88SBryant G. Ly /**
1040a28724b0SYu Zhao * pci_iov_bus_range - find bus range used by Virtual Function
1041a28724b0SYu Zhao * @bus: the PCI bus
1042a28724b0SYu Zhao *
1043a28724b0SYu Zhao * Returns max number of buses (exclude current one) used by Virtual
1044a28724b0SYu Zhao * Functions.
1045a28724b0SYu Zhao */
pci_iov_bus_range(struct pci_bus * bus)1046a28724b0SYu Zhao int pci_iov_bus_range(struct pci_bus *bus)
1047a28724b0SYu Zhao {
1048a28724b0SYu Zhao int max = 0;
1049a28724b0SYu Zhao struct pci_dev *dev;
1050a28724b0SYu Zhao
1051a28724b0SYu Zhao list_for_each_entry(dev, &bus->devices, bus_list) {
1052a28724b0SYu Zhao if (!dev->is_physfn)
1053a28724b0SYu Zhao continue;
10544449f079SWei Yang if (dev->sriov->max_VF_buses > max)
10554449f079SWei Yang max = dev->sriov->max_VF_buses;
1056a28724b0SYu Zhao }
1057a28724b0SYu Zhao
1058a28724b0SYu Zhao return max ? max - bus->number : 0;
1059a28724b0SYu Zhao }
1060dd7cc44dSYu Zhao
1061dd7cc44dSYu Zhao /**
1062dd7cc44dSYu Zhao * pci_enable_sriov - enable the SR-IOV capability
1063dd7cc44dSYu Zhao * @dev: the PCI device
106452a8873bSRandy Dunlap * @nr_virtfn: number of virtual functions to enable
1065dd7cc44dSYu Zhao *
1066dd7cc44dSYu Zhao * Returns 0 on success, or negative on failure.
1067dd7cc44dSYu Zhao */
pci_enable_sriov(struct pci_dev * dev,int nr_virtfn)1068dd7cc44dSYu Zhao int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
1069dd7cc44dSYu Zhao {
1070dd7cc44dSYu Zhao might_sleep();
1071dd7cc44dSYu Zhao
1072dd7cc44dSYu Zhao if (!dev->is_physfn)
1073652d1100SStefan Assmann return -ENOSYS;
1074dd7cc44dSYu Zhao
1075dd7cc44dSYu Zhao return sriov_enable(dev, nr_virtfn);
1076dd7cc44dSYu Zhao }
1077dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_enable_sriov);
1078dd7cc44dSYu Zhao
1079dd7cc44dSYu Zhao /**
1080dd7cc44dSYu Zhao * pci_disable_sriov - disable the SR-IOV capability
1081dd7cc44dSYu Zhao * @dev: the PCI device
1082dd7cc44dSYu Zhao */
pci_disable_sriov(struct pci_dev * dev)1083dd7cc44dSYu Zhao void pci_disable_sriov(struct pci_dev *dev)
1084dd7cc44dSYu Zhao {
1085dd7cc44dSYu Zhao might_sleep();
1086dd7cc44dSYu Zhao
1087dd7cc44dSYu Zhao if (!dev->is_physfn)
1088dd7cc44dSYu Zhao return;
1089dd7cc44dSYu Zhao
1090dd7cc44dSYu Zhao sriov_disable(dev);
1091dd7cc44dSYu Zhao }
1092dd7cc44dSYu Zhao EXPORT_SYMBOL_GPL(pci_disable_sriov);
109374bb1bccSYu Zhao
109474bb1bccSYu Zhao /**
1095fb8a0d9dSWilliams, Mitch A * pci_num_vf - return number of VFs associated with a PF device_release_driver
1096fb8a0d9dSWilliams, Mitch A * @dev: the PCI device
1097fb8a0d9dSWilliams, Mitch A *
1098fb8a0d9dSWilliams, Mitch A * Returns number of VFs, or 0 if SR-IOV is not enabled.
1099fb8a0d9dSWilliams, Mitch A */
pci_num_vf(struct pci_dev * dev)1100fb8a0d9dSWilliams, Mitch A int pci_num_vf(struct pci_dev *dev)
1101fb8a0d9dSWilliams, Mitch A {
11021452cd76SBjorn Helgaas if (!dev->is_physfn)
1103fb8a0d9dSWilliams, Mitch A return 0;
11041452cd76SBjorn Helgaas
11056b136724SBjorn Helgaas return dev->sriov->num_VFs;
1106fb8a0d9dSWilliams, Mitch A }
1107fb8a0d9dSWilliams, Mitch A EXPORT_SYMBOL_GPL(pci_num_vf);
1108bff73156SDonald Dutile
1109bff73156SDonald Dutile /**
11105a8eb242SAlexander Duyck * pci_vfs_assigned - returns number of VFs are assigned to a guest
11115a8eb242SAlexander Duyck * @dev: the PCI device
11125a8eb242SAlexander Duyck *
11135a8eb242SAlexander Duyck * Returns number of VFs belonging to this device that are assigned to a guest.
1114652d1100SStefan Assmann * If device is not a physical function returns 0.
11155a8eb242SAlexander Duyck */
pci_vfs_assigned(struct pci_dev * dev)11165a8eb242SAlexander Duyck int pci_vfs_assigned(struct pci_dev *dev)
11175a8eb242SAlexander Duyck {
11185a8eb242SAlexander Duyck struct pci_dev *vfdev;
11195a8eb242SAlexander Duyck unsigned int vfs_assigned = 0;
11205a8eb242SAlexander Duyck unsigned short dev_id;
11215a8eb242SAlexander Duyck
11225a8eb242SAlexander Duyck /* only search if we are a PF */
11235a8eb242SAlexander Duyck if (!dev->is_physfn)
11245a8eb242SAlexander Duyck return 0;
11255a8eb242SAlexander Duyck
11265a8eb242SAlexander Duyck /*
11275a8eb242SAlexander Duyck * determine the device ID for the VFs, the vendor ID will be the
11285a8eb242SAlexander Duyck * same as the PF so there is no need to check for that one
11295a8eb242SAlexander Duyck */
11303142d832SFilippo Sironi dev_id = dev->sriov->vf_device;
11315a8eb242SAlexander Duyck
11325a8eb242SAlexander Duyck /* loop through all the VFs to see if we own any that are assigned */
11335a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, NULL);
11345a8eb242SAlexander Duyck while (vfdev) {
11355a8eb242SAlexander Duyck /*
11365a8eb242SAlexander Duyck * It is considered assigned if it is a virtual function with
11375a8eb242SAlexander Duyck * our dev as the physical function and the assigned bit is set
11385a8eb242SAlexander Duyck */
11395a8eb242SAlexander Duyck if (vfdev->is_virtfn && (vfdev->physfn == dev) &&
1140be63497cSEthan Zhao pci_is_dev_assigned(vfdev))
11415a8eb242SAlexander Duyck vfs_assigned++;
11425a8eb242SAlexander Duyck
11435a8eb242SAlexander Duyck vfdev = pci_get_device(dev->vendor, dev_id, vfdev);
11445a8eb242SAlexander Duyck }
11455a8eb242SAlexander Duyck
11465a8eb242SAlexander Duyck return vfs_assigned;
11475a8eb242SAlexander Duyck }
11485a8eb242SAlexander Duyck EXPORT_SYMBOL_GPL(pci_vfs_assigned);
11495a8eb242SAlexander Duyck
11505a8eb242SAlexander Duyck /**
1151bff73156SDonald Dutile * pci_sriov_set_totalvfs -- reduce the TotalVFs available
1152bff73156SDonald Dutile * @dev: the PCI PF device
11532094f167SRandy Dunlap * @numvfs: number that should be used for TotalVFs supported
1154bff73156SDonald Dutile *
1155bff73156SDonald Dutile * Should be called from PF driver's probe routine with
1156bff73156SDonald Dutile * device's mutex held.
1157bff73156SDonald Dutile *
1158bff73156SDonald Dutile * Returns 0 if PF is an SRIOV-capable device and
1159652d1100SStefan Assmann * value of numvfs valid. If not a PF return -ENOSYS;
1160652d1100SStefan Assmann * if numvfs is invalid return -EINVAL;
1161bff73156SDonald Dutile * if VFs already enabled, return -EBUSY.
1162bff73156SDonald Dutile */
pci_sriov_set_totalvfs(struct pci_dev * dev,u16 numvfs)1163bff73156SDonald Dutile int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
1164bff73156SDonald Dutile {
1165652d1100SStefan Assmann if (!dev->is_physfn)
1166652d1100SStefan Assmann return -ENOSYS;
116751259d00SBjorn Helgaas
1168652d1100SStefan Assmann if (numvfs > dev->sriov->total_VFs)
1169bff73156SDonald Dutile return -EINVAL;
1170bff73156SDonald Dutile
1171bff73156SDonald Dutile /* Shouldn't change if VFs already enabled */
1172bff73156SDonald Dutile if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE)
1173bff73156SDonald Dutile return -EBUSY;
1174bff73156SDonald Dutile
117551259d00SBjorn Helgaas dev->sriov->driver_max_VFs = numvfs;
1176bff73156SDonald Dutile return 0;
1177bff73156SDonald Dutile }
1178bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs);
1179bff73156SDonald Dutile
1180bff73156SDonald Dutile /**
1181ddc191f5SJonghwan Choi * pci_sriov_get_totalvfs -- get total VFs supported on this device
1182bff73156SDonald Dutile * @dev: the PCI PF device
1183bff73156SDonald Dutile *
1184bff73156SDonald Dutile * For a PCIe device with SRIOV support, return the PCIe
11856b136724SBjorn Helgaas * SRIOV capability value of TotalVFs or the value of driver_max_VFs
1186652d1100SStefan Assmann * if the driver reduced it. Otherwise 0.
1187bff73156SDonald Dutile */
pci_sriov_get_totalvfs(struct pci_dev * dev)1188bff73156SDonald Dutile int pci_sriov_get_totalvfs(struct pci_dev *dev)
1189bff73156SDonald Dutile {
11901452cd76SBjorn Helgaas if (!dev->is_physfn)
1191652d1100SStefan Assmann return 0;
1192bff73156SDonald Dutile
11936b136724SBjorn Helgaas return dev->sriov->driver_max_VFs;
1194bff73156SDonald Dutile }
1195bff73156SDonald Dutile EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs);
11968effc395SAlexander Duyck
11978effc395SAlexander Duyck /**
11988effc395SAlexander Duyck * pci_sriov_configure_simple - helper to configure SR-IOV
11998effc395SAlexander Duyck * @dev: the PCI device
12008effc395SAlexander Duyck * @nr_virtfn: number of virtual functions to enable, 0 to disable
12018effc395SAlexander Duyck *
12028effc395SAlexander Duyck * Enable or disable SR-IOV for devices that don't require any PF setup
12038effc395SAlexander Duyck * before enabling SR-IOV. Return value is negative on error, or number of
12048effc395SAlexander Duyck * VFs allocated on success.
12058effc395SAlexander Duyck */
pci_sriov_configure_simple(struct pci_dev * dev,int nr_virtfn)12068effc395SAlexander Duyck int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
12078effc395SAlexander Duyck {
12088effc395SAlexander Duyck int rc;
12098effc395SAlexander Duyck
12108effc395SAlexander Duyck might_sleep();
12118effc395SAlexander Duyck
12128effc395SAlexander Duyck if (!dev->is_physfn)
12138effc395SAlexander Duyck return -ENODEV;
12148effc395SAlexander Duyck
12158effc395SAlexander Duyck if (pci_vfs_assigned(dev)) {
12168effc395SAlexander Duyck pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n");
12178effc395SAlexander Duyck return -EPERM;
12188effc395SAlexander Duyck }
12198effc395SAlexander Duyck
12208effc395SAlexander Duyck if (nr_virtfn == 0) {
12218effc395SAlexander Duyck sriov_disable(dev);
12228effc395SAlexander Duyck return 0;
12238effc395SAlexander Duyck }
12248effc395SAlexander Duyck
12258effc395SAlexander Duyck rc = sriov_enable(dev, nr_virtfn);
12268effc395SAlexander Duyck if (rc < 0)
12278effc395SAlexander Duyck return rc;
12288effc395SAlexander Duyck
12298effc395SAlexander Duyck return nr_virtfn;
12308effc395SAlexander Duyck }
12318effc395SAlexander Duyck EXPORT_SYMBOL_GPL(pci_sriov_configure_simple);
1232