s390/pci: fix hotplug module init

Loading the pci hotplug module when no devices are present will fail
but unfortunately some hotplug callbacks stay registered to the pci
bus level. Fix this by not letting module loading fail when no pci
devices are present and provide proper {de}registration functions
for these callbacks.

Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index aa74409..27b4c17 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -51,8 +51,7 @@
 DEFINE_MUTEX(zpci_list_lock);
 EXPORT_SYMBOL_GPL(zpci_list_lock);
 
-struct pci_hp_callback_ops hotplug_ops;
-EXPORT_SYMBOL_GPL(hotplug_ops);
+static struct pci_hp_callback_ops *hotplug_ops;
 
 static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
 static DEFINE_SPINLOCK(zpci_domain_lock);
@@ -974,8 +973,8 @@
 
 	mutex_lock(&zpci_list_lock);
 	list_add_tail(&zdev->entry, &zpci_list);
-	if (hotplug_ops.create_slot)
-		hotplug_ops.create_slot(zdev);
+	if (hotplug_ops)
+		hotplug_ops->create_slot(zdev);
 	mutex_unlock(&zpci_list_lock);
 
 	if (zdev->state == ZPCI_FN_STATE_STANDBY)
@@ -989,8 +988,8 @@
 out_start:
 	mutex_lock(&zpci_list_lock);
 	list_del(&zdev->entry);
-	if (hotplug_ops.remove_slot)
-		hotplug_ops.remove_slot(zdev);
+	if (hotplug_ops)
+		hotplug_ops->remove_slot(zdev);
 	mutex_unlock(&zpci_list_lock);
 out_bus:
 	zpci_free_domain(zdev);
@@ -1072,6 +1071,22 @@
 	kmem_cache_destroy(zdev_fmb_cache);
 }
 
+void zpci_register_hp_ops(struct pci_hp_callback_ops *ops)
+{
+	mutex_lock(&zpci_list_lock);
+	hotplug_ops = ops;
+	mutex_unlock(&zpci_list_lock);
+}
+EXPORT_SYMBOL_GPL(zpci_register_hp_ops);
+
+void zpci_deregister_hp_ops(void)
+{
+	mutex_lock(&zpci_list_lock);
+	hotplug_ops = NULL;
+	mutex_unlock(&zpci_list_lock);
+}
+EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
+
 unsigned int s390_pci_probe = 1;
 EXPORT_SYMBOL_GPL(s390_pci_probe);