]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/pci: Pull search for parent PF out of zpci_iov_setup_virtfn()
authorNiklas Schnelle <schnelle@linux.ibm.com>
Fri, 7 Feb 2025 12:30:16 +0000 (13:30 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 11 Feb 2025 18:35:08 +0000 (19:35 +0100)
This creates a new zpci_iov_find_parent_pf() function which a future
commit can use to find if a VF has a configured parent PF. Use
zdev->rid instead of zdev->devfn such that the new function can be used
before it has been decided if the RID will be exposed and zdev->devfn is
set. Also handle the hypotheical case that the RID is not available but
there is an otherwise matching zbus.

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_iov.c

index ead062bf2b41cc3aaec495a79baeadb9286e17d7..c7fdf5e79b3cc3b2bd75f6ba1ad48f3564f11991 100644 (file)
@@ -60,18 +60,35 @@ static int zpci_iov_link_virtfn(struct pci_dev *pdev, struct pci_dev *virtfn, in
        return 0;
 }
 
-int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn)
+/**
+ * zpci_iov_find_parent_pf - Find the parent PF, if any, of the given function
+ * @zbus:      The bus that the PCI function is on, or would be added on
+ * @zdev:      The PCI function
+ *
+ * Finds the parent PF, if it exists and is configured, of the given PCI function
+ * and increments its refcount. Th PF is searched for on the provided bus so the
+ * caller has to ensure that this is the correct bus to search. This function may
+ * be used before adding the PCI function to a zbus.
+ *
+ * Return: Pointer to the struct pci_dev of the parent PF or NULL if it not
+ * 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)
 {
-       int i, cand_devfn;
-       struct zpci_dev *zdev;
+       int i, vfid, devfn, cand_devfn;
        struct pci_dev *pdev;
-       int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
-       int rc = 0;
 
        if (!zbus->multifunction)
-               return 0;
-
-       /* If the parent PF for the given VF is also configured in the
+               return NULL;
+       /* Non-VFs and VFs without RID available don't have a parent */
+       if (!zdev->vfn || !zdev->rid_available)
+               return NULL;
+       /* Linux vfid starts at 0 vfn at 1 */
+       vfid = zdev->vfn - 1;
+       devfn = zdev->rid & ZPCI_RID_MASK_DEVFN;
+       /*
+        * If the parent PF for the given VF is also configured in the
         * instance, it must be on the same zbus.
         * We can then identify the parent PF by checking what
         * devfn the VF would have if it belonged to that PF using the PF's
@@ -85,15 +102,26 @@ int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn
                        if (!pdev)
                                continue;
                        cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
-                       if (cand_devfn == virtfn->devfn) {
-                               rc = zpci_iov_link_virtfn(pdev, virtfn, vfid);
-                               /* balance pci_get_slot() */
-                               pci_dev_put(pdev);
-                               break;
-                       }
+                       if (cand_devfn == devfn)
+                               return pdev;
                        /* balance pci_get_slot() */
                        pci_dev_put(pdev);
                }
        }
+       return NULL;
+}
+
+int zpci_iov_setup_virtfn(struct zpci_bus *zbus, struct pci_dev *virtfn, int vfn)
+{
+       struct zpci_dev *zdev = to_zpci(virtfn);
+       struct pci_dev *pdev_pf;
+       int rc = 0;
+
+       pdev_pf = zpci_iov_find_parent_pf(zbus, zdev);
+       if (pdev_pf) {
+               /* Linux' vfids start at 0 while zdev->vfn starts at 1 */
+               rc = zpci_iov_link_virtfn(pdev_pf, virtfn, zdev->vfn - 1);
+               pci_dev_put(pdev_pf);
+       }
        return rc;
 }