]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390/pci: Fix handling of isolated VFs
authorNiklas Schnelle <schnelle@linux.ibm.com>
Fri, 7 Feb 2025 12:30:17 +0000 (13:30 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 11 Feb 2025 18:35:08 +0000 (19:35 +0100)
In contrast to the commit message of the fixed commit VFs whose parent
PF is not configured are not always isolated, that is put on their own
PCI domain. This is because for VFs to be added to an existing PCI
domain it is enough for that PCI domain to share the same topology ID or
PCHID. Such a matching PCI domain without a parent PF may exist when
a PF from the same PCI card created the domain with the VF being a child
of a different, non accessible, PF. While not causing technical issues
it makes the rules which VFs are isolated inconsistent.

Fix this by explicitly checking that the parent PF exists on the PCI
domain determined by the topology ID or PCHID before registering the VF.
This works because a parent PF which is under control of this Linux
instance must be enabled and configured at the point where its child VFs
appear because otherwise SR-IOV could not have been enabled on the
parent.

Fixes: 25f39d3dcb48 ("s390/pci: Ignore RID for isolated VFs")
Cc: stable@vger.kernel.org
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/pci/pci_bus.c
arch/s390/pci/pci_iov.c
arch/s390/pci/pci_iov.h

index 857afbc4828f0c677f88cc80dd4a5fff104a615a..39a481ec4a402dbcd7e4c757fe77115c0ed5e81c 100644 (file)
@@ -331,6 +331,17 @@ error:
        return rc;
 }
 
+static bool zpci_bus_is_isolated_vf(struct zpci_bus *zbus, struct zpci_dev *zdev)
+{
+       struct pci_dev *pdev;
+
+       pdev = zpci_iov_find_parent_pf(zbus, zdev);
+       if (!pdev)
+               return true;
+       pci_dev_put(pdev);
+       return false;
+}
+
 int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
 {
        bool topo_is_tid = zdev->tid_avail;
@@ -345,6 +356,15 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
 
        topo = topo_is_tid ? zdev->tid : zdev->pchid;
        zbus = zpci_bus_get(topo, topo_is_tid);
+       /*
+        * An isolated VF gets its own domain/bus even if there exists
+        * a matching domain/bus already
+        */
+       if (zbus && zpci_bus_is_isolated_vf(zbus, zdev)) {
+               zpci_bus_put(zbus);
+               zbus = NULL;
+       }
+
        if (!zbus) {
                zbus = zpci_bus_alloc(topo, topo_is_tid);
                if (!zbus)
index c7fdf5e79b3cc3b2bd75f6ba1ad48f3564f11991..191e56a623f62c931818f5a6a0f3457e50ab0f26 100644 (file)
@@ -74,7 +74,7 @@ static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, in
  * found. If the function is not a VF or has no RequesterID information,
  * NULL is returned as well.
  */
-static struct pci_dev *zpci_iov_find_parent_pf(struct zpci_bus *zbus, struct zpci_dev *zdev)
+struct pci_dev *zpci_iov_find_parent_pf(struct zpci_bus *zbus, struct zpci_dev *zdev)
 {
        int i, vfid, devfn, cand_devfn;
        struct pci_dev *pdev;
index e3fa4e77fc867adbf968ede1f22807ffac6278da..d2c2793eb0f3483f93fefaa36b406c2512968d8d 100644 (file)
@@ -19,6 +19,8 @@ void zpci_iov_map_resources(struct pci_dev *pdev);
 
 int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn);
 
+struct pci_dev *zpci_iov_find_parent_pf(struct zpci_bus *zbus, struct zpci_dev *zdev);
+
 #else /* CONFIG_PCI_IOV */
 static inline void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn) {}
 
@@ -28,5 +30,10 @@ static inline int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *v
 {
        return 0;
 }
+
+static inline struct pci_dev *zpci_iov_find_parent_pf(struct zpci_bus *zbus, struct zpci_dev *zdev)
+{
+       return NULL;
+}
 #endif /* CONFIG_PCI_IOV */
 #endif /* __S390_PCI_IOV_h */