summaryrefslogtreecommitdiff
path: root/arch/s390/pci/pci.c
diff options
context:
space:
mode:
authorNiklas Schnelle <schnelle@linux.ibm.com>2021-02-12 16:19:31 +0300
committerHeiko Carstens <hca@linux.ibm.com>2021-04-12 13:46:42 +0300
commita50297cf8235b062bcdeaa8b1dad58e69d3e1b43 (patch)
tree12be5624238a016ed1c88f1ad6b3a571a7694f5d /arch/s390/pci/pci.c
parent7dc697d6b2b5299ab7e09c592d727671a3859be2 (diff)
downloadlinux-a50297cf8235b062bcdeaa8b1dad58e69d3e1b43.tar.xz
s390/pci: separate zbus creation from scanning
In the existing code the creation of the PCI bus and the scanning of function zero all happens in zpci_scan_bus(). This in turn requires functions to be enabled and their resources to be available before the PCI bus is even created. This not only means that functions are enabled long before they are actually made available to the common PCI subsystem. In case of functions with non-zero devfn which appeared before the function with devfn zero they can wait arbitrarily long in this enabled but not scanned state. Fix this by separating the creation of the PCI bus from scanning it and only prepare, that is enable and setup MMIO bus resources, functions just before they are scanned. As they may be scanned multiple times track if we already created resources in the zdev. 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>
Diffstat (limited to 'arch/s390/pci/pci.c')
-rw-r--r--arch/s390/pci/pci.c42
1 files changed, 13 insertions, 29 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 0bce6078bfd6..023c3c2ab7f1 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -538,6 +538,7 @@ int zpci_setup_bus_resources(struct zpci_dev *zdev,
zdev->bars[i].res = res;
pci_add_resource(resources, res);
}
+ zdev->has_resources = 1;
return 0;
}
@@ -554,6 +555,7 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
release_resource(zdev->bars[i].res);
kfree(zdev->bars[i].res);
}
+ zdev->has_resources = 0;
}
int pcibios_add_device(struct pci_dev *pdev)
@@ -717,15 +719,9 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
if (rc)
goto error;
- if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
- rc = zpci_enable_device(zdev);
- if (rc)
- goto error_destroy_iommu;
- }
-
rc = zpci_bus_device_register(zdev, &pci_root_ops);
if (rc)
- goto error_disable;
+ goto error_destroy_iommu;
spin_lock(&zpci_list_lock);
list_add_tail(&zdev->entry, &zpci_list);
@@ -733,9 +729,6 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
return 0;
-error_disable:
- if (zdev_enabled(zdev))
- zpci_disable_device(zdev);
error_destroy_iommu:
zpci_destroy_iommu(zdev);
error:
@@ -751,7 +744,8 @@ error:
*
* Configuring a device includes the configuration itself, if not done by the
* platform, enabling, scanning and adding it to the common code PCI subsystem.
- * If any failure occurs, the zpci_dev is left in Standby.
+ * If any failure occurs, the zpci_dev is left disabled either in Standby if
+ * the configuration failed or Configured if enabling or scanning failed.
*
* Return: 0 on success, or an error code otherwise
*/
@@ -768,29 +762,19 @@ int zpci_configure_device(struct zpci_dev *zdev, u32 fh)
zdev->state = ZPCI_FN_STATE_CONFIGURED;
}
- rc = zpci_enable_device(zdev);
- if (rc)
- goto error;
-
/* the PCI function will be scanned once function 0 appears */
if (!zdev->zbus->bus)
return 0;
- rc = zpci_bus_scan_device(zdev);
- if (rc)
- goto error_disable;
-
- return 0;
+ /* For function 0 on a multi-function bus scan whole bus as we might
+ * have to pick up existing functions waiting for it to allow creating
+ * the PCI bus
+ */
+ if (zdev->devfn == 0 && zdev->zbus->multifunction)
+ rc = zpci_bus_scan_bus(zdev->zbus);
+ else
+ rc = zpci_bus_scan_device(zdev);
-error_disable:
- zpci_disable_device(zdev);
-error:
- if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
- rc = sclp_pci_deconfigure(zdev->fid);
- zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, rc);
- if (!rc)
- zdev->state = ZPCI_FN_STATE_STANDBY;
- }
return rc;
}