summaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/s390_pci_hpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/s390_pci_hpc.c')
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index 46a7b738f61f..ea3fa90d020a 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -41,6 +41,28 @@ struct slot {
struct zpci_dev *zdev;
};
+static inline int slot_configure(struct slot *slot)
+{
+ int ret = sclp_pci_configure(slot->zdev->fid);
+
+ zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret);
+ if (!ret)
+ slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
+
+ return ret;
+}
+
+static inline int slot_deconfigure(struct slot *slot)
+{
+ int ret = sclp_pci_deconfigure(slot->zdev->fid);
+
+ zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret);
+ if (!ret)
+ slot->zdev->state = ZPCI_FN_STATE_STANDBY;
+
+ return ret;
+}
+
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
@@ -49,14 +71,23 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
if (slot->zdev->state != ZPCI_FN_STATE_STANDBY)
return -EIO;
- rc = sclp_pci_configure(slot->zdev->fid);
- zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, rc);
- if (!rc) {
- slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
- /* automatically scan the device after is was configured */
- zpci_enable_device(slot->zdev);
- zpci_scan_device(slot->zdev);
- }
+ rc = slot_configure(slot);
+ if (rc)
+ return rc;
+
+ rc = zpci_enable_device(slot->zdev);
+ if (rc)
+ goto out_deconfigure;
+
+ slot->zdev->state = ZPCI_FN_STATE_ONLINE;
+
+ pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
+ pci_bus_add_devices(slot->zdev->bus);
+
+ return rc;
+
+out_deconfigure:
+ slot_deconfigure(slot);
return rc;
}
@@ -68,17 +99,14 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
if (!zpci_fn_configured(slot->zdev->state))
return -EIO;
+ if (slot->zdev->pdev)
+ pci_stop_and_remove_bus_device(slot->zdev->pdev);
+
rc = zpci_disable_device(slot->zdev);
if (rc)
return rc;
- /* TODO: we rely on the user to unbind/remove the device, is that plausible
- * or do we need to trigger that here?
- */
- rc = sclp_pci_deconfigure(slot->zdev->fid);
- zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, rc);
- if (!rc)
- slot->zdev->state = ZPCI_FN_STATE_STANDBY;
- return rc;
+
+ return slot_deconfigure(slot);
}
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)