summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/css.c65
-rw-r--r--drivers/s390/cio/device.c20
-rw-r--r--drivers/s390/cio/device.h1
3 files changed, 61 insertions, 25 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 393c73c47f8..95805da2bb2 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -601,8 +601,7 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
css_evaluate_subchannel(mchk_schid, 0);
}
-static int __init
-__init_channel_subsystem(struct subchannel_id schid, void *data)
+static int __init setup_subchannel(struct subchannel_id schid, void *data)
{
struct subchannel *sch;
int ret;
@@ -854,14 +853,13 @@ static struct notifier_block css_power_notifier = {
* The struct subchannel's are created during probing (except for the
* static console subchannel).
*/
-static int __init
-init_channel_subsystem (void)
+static int __init css_bus_init(void)
{
int ret, i;
ret = chsc_determine_css_characteristics();
if (ret == -ENOMEM)
- goto out; /* No need to continue. */
+ goto out;
ret = chsc_alloc_sei_area();
if (ret)
@@ -934,7 +932,6 @@ init_channel_subsystem (void)
/* Enable default isc for I/O subchannels. */
isc_register(IO_SCH_ISC);
- for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
out_file:
if (css_chsc_characteristics.secm)
@@ -966,6 +963,60 @@ out:
return ret;
}
+static void __init css_bus_cleanup(void)
+{
+ struct channel_subsystem *css;
+ int i;
+
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ css = channel_subsystems[i];
+ device_unregister(&css->pseudo_subchannel->dev);
+ css->pseudo_subchannel = NULL;
+ if (css_chsc_characteristics.secm)
+ device_remove_file(&css->device, &dev_attr_cm_enable);
+ device_unregister(&css->device);
+ }
+ bus_unregister(&css_bus_type);
+ crw_unregister_handler(CRW_RSC_CSS);
+ chsc_free_sei_area();
+ kfree(slow_subchannel_set);
+ isc_unregister(IO_SCH_ISC);
+}
+
+static int __init channel_subsystem_init(void)
+{
+ int ret;
+
+ ret = css_bus_init();
+ if (ret)
+ return ret;
+
+ ret = io_subchannel_init();
+ if (ret)
+ css_bus_cleanup();
+
+ return ret;
+}
+subsys_initcall(channel_subsystem_init);
+
+/*
+ * Wait for the initialization of devices to finish, to make sure we are
+ * done with our setup if the search for the root device starts.
+ */
+static int __init channel_subsystem_init_sync(void)
+{
+ /* Allocate and register subchannels. */
+ for_each_subchannel(setup_subchannel, NULL);
+
+ /* Wait for the initialization of ccw devices to finish. */
+ wait_event(ccw_device_init_wq,
+ atomic_read(&ccw_device_init_count) == 0);
+ flush_workqueue(ccw_device_work);
+
+ return 0;
+}
+subsys_initcall_sync(channel_subsystem_init_sync);
+
int sch_is_pseudo_sch(struct subchannel *sch)
{
return sch == to_css(sch->dev.parent)->pseudo_subchannel;
@@ -1135,7 +1186,5 @@ void css_driver_unregister(struct css_driver *cdrv)
}
EXPORT_SYMBOL_GPL(css_driver_unregister);
-subsys_initcall(init_channel_subsystem);
-
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(css_bus_type);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 6527f3f3449..4093adc12f2 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -170,8 +170,7 @@ atomic_t ccw_device_init_count;
static void recovery_func(unsigned long data);
-static int __init
-init_ccw_bus_type (void)
+int __init io_subchannel_init(void)
{
int ret;
@@ -181,10 +180,10 @@ init_ccw_bus_type (void)
ccw_device_work = create_singlethread_workqueue("cio");
if (!ccw_device_work)
- return -ENOMEM; /* FIXME: better errno ? */
+ return -ENOMEM;
slow_path_wq = create_singlethread_workqueue("kslowcrw");
if (!slow_path_wq) {
- ret = -ENOMEM; /* FIXME: better errno ? */
+ ret = -ENOMEM;
goto out_err;
}
if ((ret = bus_register (&ccw_bus_type)))
@@ -194,9 +193,6 @@ init_ccw_bus_type (void)
if (ret)
goto out_err;
- wait_event(ccw_device_init_wq,
- atomic_read(&ccw_device_init_count) == 0);
- flush_workqueue(ccw_device_work);
return 0;
out_err:
if (ccw_device_work)
@@ -206,16 +202,6 @@ out_err:
return ret;
}
-static void __exit
-cleanup_ccw_bus_type (void)
-{
- css_driver_unregister(&io_subchannel_driver);
- bus_unregister(&ccw_bus_type);
- destroy_workqueue(ccw_device_work);
-}
-
-subsys_initcall(init_ccw_bus_type);
-module_exit(cleanup_ccw_bus_type);
/************************ device handling **************************/
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index e3975107a57..ed39a2caaf4 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -74,6 +74,7 @@ dev_fsm_final_state(struct ccw_device *cdev)
extern struct workqueue_struct *ccw_device_work;
extern wait_queue_head_t ccw_device_init_wq;
extern atomic_t ccw_device_init_count;
+int __init io_subchannel_init(void);
void io_subchannel_recog_done(struct ccw_device *cdev);
void io_subchannel_init_config(struct subchannel *sch);