aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/pci.h2
-rw-r--r--arch/s390/pci/pci.c11
-rw-r--r--arch/s390/pci/pci_bus.c35
-rw-r--r--arch/s390/pci/pci_bus.h1
-rw-r--r--arch/s390/pci/pci_event.c14
5 files changed, 33 insertions, 30 deletions
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index d810ea4d358f..35c2af9371a9 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -201,7 +201,7 @@ extern unsigned int s390_pci_no_rid;
Prototypes
----------------------------------------------------------------------------- */
/* Base stuff */
-int zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
+struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
int zpci_enable_device(struct zpci_dev *);
int zpci_disable_device(struct zpci_dev *);
int zpci_configure_device(struct zpci_dev *zdev, u32 fh);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 023c3c2ab7f1..d6c6b5119a14 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -690,9 +690,9 @@ int zpci_disable_device(struct zpci_dev *zdev)
* Creates a new zpci device and adds it to its, possibly newly created, zbus
* as well as zpci_list.
*
- * Returns: 0 on success, an error value otherwise
+ * Returns: the zdev on success or an error pointer otherwise
*/
-int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
+struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
{
struct zpci_dev *zdev;
int rc;
@@ -700,7 +700,7 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, state);
zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
if (!zdev)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
/* FID and Function Handle are the static/dynamic identifiers */
zdev->fid = fid;
@@ -727,14 +727,14 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
list_add_tail(&zdev->entry, &zpci_list);
spin_unlock(&zpci_list_lock);
- return 0;
+ return zdev;
error_destroy_iommu:
zpci_destroy_iommu(zdev);
error:
zpci_dbg(0, "add fid:%x, rc:%d\n", fid, rc);
kfree(zdev);
- return rc;
+ return ERR_PTR(rc);
}
/**
@@ -959,6 +959,7 @@ static int __init pci_base_init(void)
rc = clp_scan_pci_devices();
if (rc)
goto out_find;
+ zpci_bus_scan_busses();
s390_pci_initialized = 1;
return 0;
diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c
index 9bc869afe011..9629f9779c79 100644
--- a/arch/s390/pci/pci_bus.c
+++ b/arch/s390/pci/pci_bus.c
@@ -160,6 +160,23 @@ int zpci_bus_scan_bus(struct zpci_bus *zbus)
return ret;
}
+/* zpci_bus_scan_busses - Scan all registered busses
+ *
+ * Scan all available zbusses
+ *
+ */
+void zpci_bus_scan_busses(void)
+{
+ struct zpci_bus *zbus = NULL;
+
+ mutex_lock(&zbus_list_lock);
+ list_for_each_entry(zbus, &zbus_list, bus_next) {
+ zpci_bus_scan_bus(zbus);
+ cond_resched();
+ }
+ mutex_unlock(&zbus_list_lock);
+}
+
/* zpci_bus_create_pci_bus - Create the PCI bus associated with this zbus
* @zbus: the zbus holding the zdevices
* @f0: function 0 of the bus
@@ -387,24 +404,6 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
if (rc)
goto error;
- if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
- return 0;
-
- /* the PCI function will be scanned once function 0 appears */
- if (!zdev->zbus->bus)
- return 0;
-
- /* For function 0 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);
-
- if (rc)
- goto error;
-
return 0;
error:
diff --git a/arch/s390/pci/pci_bus.h b/arch/s390/pci/pci_bus.h
index 981876ae3bd7..b877a97e6745 100644
--- a/arch/s390/pci/pci_bus.h
+++ b/arch/s390/pci/pci_bus.h
@@ -11,6 +11,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_bus(struct zpci_bus *zbus);
+void zpci_bus_scan_busses(void);
int zpci_bus_scan_device(struct zpci_dev *zdev);
void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
index ae3054d85491..1178b48a66df 100644
--- a/arch/s390/pci/pci_event.c
+++ b/arch/s390/pci/pci_event.c
@@ -104,13 +104,15 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
switch (ccdf->pec) {
case 0x0301: /* Reserved|Standby -> Configured */
if (!zdev) {
- zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
- break;
+ zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
+ if (IS_ERR(zdev))
+ break;
+ } else {
+ /* the configuration request may be stale */
+ if (zdev->state != ZPCI_FN_STATE_STANDBY)
+ break;
+ zdev->state = ZPCI_FN_STATE_CONFIGURED;
}
- /* the configuration request may be stale */
- if (zdev->state != ZPCI_FN_STATE_STANDBY)
- break;
- zdev->state = ZPCI_FN_STATE_CONFIGURED;
zpci_configure_device(zdev, ccdf->fh);
break;
case 0x0302: /* Reserved -> Standby */