From faf29a4d93a98b4ccd8a10297353a9d0779d231f Mon Sep 17 00:00:00 2001
From: Niklas Schnelle <schnelle@linux.ibm.com>
Date: Thu, 11 Feb 2021 14:20:03 +0100
Subject: [PATCH] s390/pci: introduce zpci_bus_scan_device()

To match zpci_bus_scan_device() and the PCI common code terminology and
to remove some code duplication, we pull the multiple uses of
pci_scan_single_device() into a function. For now this has the side
effect of adding each device to the PCI bus separately and locking and
unlocking the rescan/remove lock for each instead of just once per bus.
This is clearly less efficient but provides a correct intermediate
behavior until a follow on change does both the adding and scanning only
once per bus.

Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Acked-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>
---
 arch/s390/pci/pci.c     |  9 ++-------
 arch/s390/pci/pci_bus.c | 35 +++++++++++++++++++++++++----------
 arch/s390/pci/pci_bus.h |  1 +
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index dd14641b2d20b..0bce6078bfd63 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -757,7 +757,6 @@ error:
  */
 int zpci_configure_device(struct zpci_dev *zdev, u32 fh)
 {
-	struct pci_dev *pdev;
 	int rc;
 
 	zdev->fh = fh;
@@ -777,14 +776,10 @@ int zpci_configure_device(struct zpci_dev *zdev, u32 fh)
 	if (!zdev->zbus->bus)
 		return 0;
 
-	pdev = pci_scan_single_device(zdev->zbus->bus, zdev->devfn);
-	if (!pdev)
+	rc = zpci_bus_scan_device(zdev);
+	if (rc)
 		goto error_disable;
 
-	pci_bus_add_device(pdev);
-	pci_lock_rescan_remove();
-	pci_bus_add_devices(zdev->zbus->bus);
-	pci_unlock_rescan_remove();
 	return 0;
 
 error_disable:
diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c
index ace9dbbe3bc14..7b37c4316e35d 100644
--- a/arch/s390/pci/pci_bus.c
+++ b/arch/s390/pci/pci_bus.c
@@ -30,6 +30,29 @@ static LIST_HEAD(zbus_list);
 static DEFINE_SPINLOCK(zbus_list_lock);
 static int zpci_nb_devices;
 
+/* zpci_bus_scan_device - Scan a single device adding it to the PCI core
+ * @zdev: the zdev to be scanned
+ *
+ * Scans the PCI function making it available to the common PCI code.
+ *
+ * Return: 0 on success, an error value otherwise
+ */
+int zpci_bus_scan_device(struct zpci_dev *zdev)
+{
+	struct pci_dev *pdev;
+
+	pdev = pci_scan_single_device(zdev->zbus->bus, zdev->devfn);
+	if (!pdev)
+		return -ENODEV;
+
+	pci_bus_add_device(pdev);
+	pci_lock_rescan_remove();
+	pci_bus_add_devices(zdev->zbus->bus);
+	pci_unlock_rescan_remove();
+
+	return 0;
+}
+
 /* zpci_bus_remove_device - Removes the given zdev from the PCI core
  * @zdev: the zdev to be removed from the PCI core
  * @set_error: if true the device's error state is set to permanent failure
@@ -176,10 +199,10 @@ void pcibios_bus_add_device(struct pci_dev *pdev)
 
 static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
 {
-	struct pci_bus *bus;
 	struct resource_entry *window, *n;
 	struct resource *res;
 	struct pci_dev *pdev;
+	struct pci_bus *bus;
 	int rc;
 
 	bus = zbus->bus;
@@ -203,11 +226,7 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
 		pci_bus_add_resource(bus, res, 0);
 	}
 
-	pdev = pci_scan_single_device(bus, zdev->devfn);
-	if (pdev)
-		pci_bus_add_device(pdev);
-
-	return 0;
+	return zpci_bus_scan_device(zdev);
 }
 
 static void zpci_bus_add_devices(struct zpci_bus *zbus)
@@ -217,10 +236,6 @@ static void zpci_bus_add_devices(struct zpci_bus *zbus)
 	for (i = 1; i < ZPCI_FUNCTIONS_PER_BUS; i++)
 		if (zbus->function[i])
 			zpci_bus_add_device(zbus, zbus->function[i]);
-
-	pci_lock_rescan_remove();
-	pci_bus_add_devices(zbus->bus);
-	pci_unlock_rescan_remove();
 }
 
 int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
diff --git a/arch/s390/pci/pci_bus.h b/arch/s390/pci/pci_bus.h
index e04ca06a71b64..2649238f6cde4 100644
--- a/arch/s390/pci/pci_bus.h
+++ b/arch/s390/pci/pci_bus.h
@@ -10,6 +10,7 @@
 int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops);
 void zpci_bus_device_unregister(struct zpci_dev *zdev);
 
+int zpci_bus_scan_device(struct zpci_dev *zdev);
 void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
 
 void zpci_release_device(struct kref *kref);
-- 
2.30.2