diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2013-01-31 18:55:17 (GMT) |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-02-14 14:55:17 (GMT) |
commit | 53923354d69e4748506bfee932b7c6b309a15c21 (patch) | |
tree | 3d6e2d0fac4f26f53cbff549ad31b0032006c99d | |
parent | add09d61fee72d7a346051332b6d99f18989504c (diff) | |
download | linux-53923354d69e4748506bfee932b7c6b309a15c21.tar.xz |
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>
-rw-r--r-- | arch/s390/include/asm/pci.h | 4 | ||||
-rw-r--r-- | arch/s390/pci/pci.c | 27 | ||||
-rw-r--r-- | drivers/pci/hotplug/s390_pci_hpc.c | 58 |
3 files changed, 49 insertions, 40 deletions
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 6383c44..05333b7 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -185,9 +185,11 @@ void zpci_dma_exit(void); /* Hotplug */ extern struct mutex zpci_list_lock; extern struct list_head zpci_list; -extern struct pci_hp_callback_ops hotplug_ops; extern unsigned int s390_pci_probe; +void zpci_register_hp_ops(struct pci_hp_callback_ops *); +void zpci_deregister_hp_ops(void); + /* FMB */ int zpci_fmb_enable_device(struct zpci_dev *); int zpci_fmb_disable_device(struct zpci_dev *); 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 @@ EXPORT_SYMBOL_GPL(zpci_list); 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 @@ int zpci_create_device(struct zpci_dev *zdev) 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 @@ int zpci_create_device(struct zpci_dev *zdev) 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 @@ static void zpci_mem_exit(void) 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); diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 8fe2a8a..7db249a 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -172,25 +172,6 @@ error: return -ENOMEM; } -static int __init init_pci_slots(void) -{ - struct zpci_dev *zdev; - int device = 0; - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - mutex_lock(&zpci_list_lock); - list_for_each_entry(zdev, &zpci_list, entry) { - init_pci_slot(zdev); - device++; - } - - mutex_unlock(&zpci_list_lock); - return (device) ? 0 : -ENODEV; -} - static void exit_pci_slot(struct zpci_dev *zdev) { struct list_head *tmp, *n; @@ -205,6 +186,26 @@ static void exit_pci_slot(struct zpci_dev *zdev) } } +static struct pci_hp_callback_ops hp_ops = { + .create_slot = init_pci_slot, + .remove_slot = exit_pci_slot, +}; + +static void __init init_pci_slots(void) +{ + struct zpci_dev *zdev; + + /* + * Create a structure for each slot, and register that slot + * with the pci_hotplug subsystem. + */ + mutex_lock(&zpci_list_lock); + list_for_each_entry(zdev, &zpci_list, entry) { + init_pci_slot(zdev); + } + mutex_unlock(&zpci_list_lock); +} + static void __exit exit_pci_slots(void) { struct list_head *tmp, *n; @@ -224,28 +225,19 @@ static void __exit exit_pci_slots(void) static int __init pci_hotplug_s390_init(void) { - /* - * Do specific initialization stuff for your driver here - * like initializing your controller hardware (if any) and - * determining the number of slots you have in the system - * right now. - */ - if (!s390_pci_probe) return -EOPNOTSUPP; - /* register callbacks for slot handling from arch code */ - mutex_lock(&zpci_list_lock); - hotplug_ops.create_slot = init_pci_slot; - hotplug_ops.remove_slot = exit_pci_slot; - mutex_unlock(&zpci_list_lock); - pr_info("registered hotplug slot callbacks\n"); - return init_pci_slots(); + zpci_register_hp_ops(&hp_ops); + init_pci_slots(); + + return 0; } static void __exit pci_hotplug_s390_exit(void) { exit_pci_slots(); + zpci_deregister_hp_ops(); } module_init(pci_hotplug_s390_init); |