diff mbox series

[SRU,F,G,1/3] s390/pci: fix zpci_bus_link_virtfn()

Message ID 20200826122230.887710-2-frank.heimes@canonical.com
State New
Headers show
Series [SRU,F,G,1/3] s390/pci: fix zpci_bus_link_virtfn() | expand

Commit Message

Frank Heimes Aug. 26, 2020, 12:22 p.m. UTC
From: Niklas Schnelle <schnelle@linux.ibm.com>

BugLink: https://bugs.launchpad.net/bugs/1892849

We were missing the pci_dev_put() for candidate PFs.  Furhtermore in
discussion with upstream it turns out that somewhat counterintuitively
some common code, in particular the vfio-pci driver, assumes that
pdev->is_virtfn always implies that pdev->physfn is set, i.e. that VFs
are always linked.
While POWER does seem to set pdev->is_virtfn even for unlinked functions
(see comments in arch/powerpc/kernel/eeh.c:eeh_debugfs_break_device())
for now just be safe and only set pdev->is_virtfn on linking.
Also make sure that we only search for parent PFs if the zbus is
multifunction and we thus know the devfn values supplied by firmware
come from the RID.

Fixes: e5794cf1a270 ("s390/pci: create links between PFs and VFs")
Cc: <stable@vger.kernel.org> # 5.8
Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
(cherry picked from commit 3cddb79afc60bcdb5fd9dd7a1c64a8d03bdd460f)
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
---
 arch/s390/pci/pci_bus.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c
index 642a99384688..423af8b1da7b 100644
--- a/arch/s390/pci/pci_bus.c
+++ b/arch/s390/pci/pci_bus.c
@@ -132,13 +132,14 @@  static int zpci_bus_link_virtfn(struct pci_dev *pdev,
 {
 	int rc;
 
-	virtfn->physfn = pci_dev_get(pdev);
 	rc = pci_iov_sysfs_link(pdev, virtfn, vfid);
-	if (rc) {
-		pci_dev_put(pdev);
-		virtfn->physfn = NULL;
+	if (rc)
 		return rc;
-	}
+
+	virtfn->is_virtfn = 1;
+	virtfn->multifunction = 0;
+	virtfn->physfn = pci_dev_get(pdev);
+
 	return 0;
 }
 
@@ -151,9 +152,9 @@  static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
 	int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
 	int rc = 0;
 
-	virtfn->is_virtfn = 1;
-	virtfn->multifunction = 0;
-	WARN_ON(vfid < 0);
+	if (!zbus->multifunction)
+		return 0;
+
 	/* 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
@@ -165,11 +166,17 @@  static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
 		zdev = zbus->function[i];
 		if (zdev && zdev->is_physfn) {
 			pdev = pci_get_slot(zbus->bus, zdev->devfn);
+			if (!pdev)
+				continue;
 			cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
 			if (cand_devfn == virtfn->devfn) {
 				rc = zpci_bus_link_virtfn(pdev, virtfn, vfid);
+				/* balance pci_get_slot() */
+				pci_dev_put(pdev);
 				break;
 			}
+			/* balance pci_get_slot() */
+			pci_dev_put(pdev);
 		}
 	}
 	return rc;
@@ -178,8 +185,6 @@  static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
 static inline int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
 		struct pci_dev *virtfn, int vfn)
 {
-	virtfn->is_virtfn = 1;
-	virtfn->multifunction = 0;
 	return 0;
 }
 #endif