|
@@ -114,6 +114,29 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
|
|
|
return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
|
|
|
}
|
|
|
|
|
|
+static void pci_read_vf_config_common(struct pci_dev *virtfn)
|
|
|
+{
|
|
|
+ struct pci_dev *physfn = virtfn->physfn;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Some config registers are the same across all associated VFs.
|
|
|
+ * Read them once from VF0 so we can skip reading them from the
|
|
|
+ * other VFs.
|
|
|
+ *
|
|
|
+ * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to
|
|
|
+ * have the same Revision ID and Subsystem ID, but we assume they
|
|
|
+ * do.
|
|
|
+ */
|
|
|
+ pci_read_config_dword(virtfn, PCI_CLASS_REVISION,
|
|
|
+ &physfn->sriov->class);
|
|
|
+ pci_read_config_byte(virtfn, PCI_HEADER_TYPE,
|
|
|
+ &physfn->sriov->hdr_type);
|
|
|
+ pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID,
|
|
|
+ &physfn->sriov->subsystem_vendor);
|
|
|
+ pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
|
|
|
+ &physfn->sriov->subsystem_device);
|
|
|
+}
|
|
|
+
|
|
|
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|
|
{
|
|
|
int i;
|
|
@@ -136,13 +159,17 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|
|
virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
|
|
|
virtfn->vendor = dev->vendor;
|
|
|
virtfn->device = iov->vf_device;
|
|
|
+ virtfn->is_virtfn = 1;
|
|
|
+ virtfn->physfn = pci_dev_get(dev);
|
|
|
+
|
|
|
+ if (id == 0)
|
|
|
+ pci_read_vf_config_common(virtfn);
|
|
|
+
|
|
|
rc = pci_setup_device(virtfn);
|
|
|
if (rc)
|
|
|
- goto failed0;
|
|
|
+ goto failed1;
|
|
|
|
|
|
virtfn->dev.parent = dev->dev.parent;
|
|
|
- virtfn->physfn = pci_dev_get(dev);
|
|
|
- virtfn->is_virtfn = 1;
|
|
|
virtfn->multifunction = 0;
|
|
|
|
|
|
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
|
@@ -163,10 +190,10 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|
|
sprintf(buf, "virtfn%u", id);
|
|
|
rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
|
|
|
if (rc)
|
|
|
- goto failed1;
|
|
|
+ goto failed2;
|
|
|
rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
|
|
|
if (rc)
|
|
|
- goto failed2;
|
|
|
+ goto failed3;
|
|
|
|
|
|
kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
|
|
|
|
|
@@ -174,11 +201,12 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
-failed2:
|
|
|
+failed3:
|
|
|
sysfs_remove_link(&dev->dev.kobj, buf);
|
|
|
+failed2:
|
|
|
+ pci_stop_and_remove_bus_device(virtfn);
|
|
|
failed1:
|
|
|
pci_dev_put(dev);
|
|
|
- pci_stop_and_remove_bus_device(virtfn);
|
|
|
failed0:
|
|
|
virtfn_remove_bus(dev->bus, bus);
|
|
|
failed:
|