From 2f17644d1cd0121daa0a997ff4eca5b3b44d1fae Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:33 +0200 Subject: [S390] cio: merge init calls Define initialization sequence of css and ccw bus init calls by merging them into a single init call. Also introduce channel_subsystem_init_sync to wait for the initialization of devices to finish. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 65 +++++++++++++++++++++++++++++++++++++++++------ drivers/s390/cio/device.c | 20 +++------------ drivers/s390/cio/device.h | 1 + 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); -- cgit v1.2.3 From 255305536c1b56ad09590f1400fb2c788265e34e Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:34 +0200 Subject: [S390] cio: introduce css_eval_scheduled Use css_eval_scheduled to determine if all scheduled subchannel evaluation is finished. Wait for this value to be 0 in the channel subsystem init function. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 16 ++++++++++++++++ drivers/s390/cio/idset.c | 10 ++++++++++ drivers/s390/cio/idset.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 95805da2bb2..59c4b94cdb4 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -409,10 +409,14 @@ static void css_evaluate_subchannel(struct subchannel_id schid, int slow) static struct idset *slow_subchannel_set; static spinlock_t slow_subchannel_lock; +static wait_queue_head_t css_eval_wq; +static atomic_t css_eval_scheduled; static int __init slow_subchannel_init(void) { spin_lock_init(&slow_subchannel_lock); + atomic_set(&css_eval_scheduled, 0); + init_waitqueue_head(&css_eval_wq); slow_subchannel_set = idset_sch_new(); if (!slow_subchannel_set) { CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n"); @@ -468,9 +472,17 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) static void css_slow_path_func(struct work_struct *unused) { + unsigned long flags; + CIO_TRACE_EVENT(4, "slowpath"); for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn, NULL); + spin_lock_irqsave(&slow_subchannel_lock, flags); + if (idset_is_empty(slow_subchannel_set)) { + atomic_set(&css_eval_scheduled, 0); + wake_up(&css_eval_wq); + } + spin_unlock_irqrestore(&slow_subchannel_lock, flags); } static DECLARE_WORK(slow_path_work, css_slow_path_func); @@ -482,6 +494,7 @@ void css_schedule_eval(struct subchannel_id schid) spin_lock_irqsave(&slow_subchannel_lock, flags); idset_sch_add(slow_subchannel_set, schid); + atomic_set(&css_eval_scheduled, 1); queue_work(slow_path_wq, &slow_path_work); spin_unlock_irqrestore(&slow_subchannel_lock, flags); } @@ -492,6 +505,7 @@ void css_schedule_eval_all(void) spin_lock_irqsave(&slow_subchannel_lock, flags); idset_fill(slow_subchannel_set); + atomic_set(&css_eval_scheduled, 1); queue_work(slow_path_wq, &slow_path_work); spin_unlock_irqrestore(&slow_subchannel_lock, flags); } @@ -1007,6 +1021,8 @@ static int __init channel_subsystem_init_sync(void) { /* Allocate and register subchannels. */ for_each_subchannel(setup_subchannel, NULL); + /* Wait for the evaluation of subchannels to finish. */ + wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); /* Wait for the initialization of ccw devices to finish. */ wait_event(ccw_device_init_wq, diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index cf8f24a4b5e..77e42cb127b 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -110,3 +110,13 @@ int idset_sch_get_first(struct idset *set, struct subchannel_id *schid) } return rc; } + +int idset_is_empty(struct idset *set) +{ + int bitnum; + + bitnum = find_first_bit(set->bitmap, set->num_ssid * set->num_id); + if (bitnum >= set->num_ssid * set->num_id) + return 1; + return 0; +} diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 528065cb502..ca1398aadc7 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -21,5 +21,6 @@ void idset_sch_add(struct idset *set, struct subchannel_id id); void idset_sch_del(struct idset *set, struct subchannel_id id); int idset_sch_contains(struct idset *set, struct subchannel_id id); int idset_sch_get_first(struct idset *set, struct subchannel_id *id); +int idset_is_empty(struct idset *set); #endif /* S390_IDSET_H */ -- cgit v1.2.3 From 8ea7f5590142c0b9ab319aa3cae85cf430a207d8 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:35 +0200 Subject: [S390] cio: introduce css_settle Introduce the css_driver callback settle which can be implemented by a subchannel driver to wait for the subchannel type specific asynchronous work to finish. In channel_subsystem_init_sync we call that for each subchannel driver. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 17 +++++++++++------ drivers/s390/cio/css.h | 2 ++ drivers/s390/cio/device.c | 18 ++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 59c4b94cdb4..f018835afdf 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1013,6 +1013,15 @@ static int __init channel_subsystem_init(void) } subsys_initcall(channel_subsystem_init); +static int css_settle(struct device_driver *drv, void *unused) +{ + struct css_driver *cssdrv = to_cssdriver(drv); + + if (cssdrv->settle) + cssdrv->settle(); + return 0; +} + /* * 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. @@ -1024,12 +1033,8 @@ static int __init channel_subsystem_init_sync(void) /* Wait for the evaluation of subchannels to finish. */ wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); - /* 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; + /* Wait for the subchannel type specific initialization to finish */ + return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle); } subsys_initcall_sync(channel_subsystem_init_sync); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 9763eeec745..54acdaade86 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -75,6 +75,7 @@ struct chp_link; * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation + * @settle: wait for asynchronous work to finish * @name: name of the device driver */ struct css_driver { @@ -92,6 +93,7 @@ struct css_driver { int (*freeze)(struct subchannel *); int (*thaw) (struct subchannel *); int (*restore)(struct subchannel *); + void (*settle)(void); const char *name; }; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 4093adc12f2..f780bdd3a04 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -131,6 +131,10 @@ static void io_subchannel_shutdown(struct subchannel *); static int io_subchannel_sch_event(struct subchannel *, int); static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, int); +static void recovery_func(unsigned long data); +struct workqueue_struct *ccw_device_work; +wait_queue_head_t ccw_device_init_wq; +atomic_t ccw_device_init_count; static struct css_device_id io_subchannel_ids[] = { { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, @@ -151,6 +155,13 @@ static int io_subchannel_prepare(struct subchannel *sch) return 0; } +static void io_subchannel_settle(void) +{ + wait_event(ccw_device_init_wq, + atomic_read(&ccw_device_init_count) == 0); + flush_workqueue(ccw_device_work); +} + static struct css_driver io_subchannel_driver = { .owner = THIS_MODULE, .subchannel_type = io_subchannel_ids, @@ -162,14 +173,9 @@ static struct css_driver io_subchannel_driver = { .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, .prepare = io_subchannel_prepare, + .settle = io_subchannel_settle, }; -struct workqueue_struct *ccw_device_work; -wait_queue_head_t ccw_device_init_wq; -atomic_t ccw_device_init_count; - -static void recovery_func(unsigned long data); - int __init io_subchannel_init(void) { int ret; -- cgit v1.2.3 From b827d1c8b65b27a293433e7c4723c7dfd6c4b848 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:36 +0200 Subject: [S390] cio: dont kfree vmalloced memory Don't use kfree to free memory allocated by vmalloc. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index f018835afdf..b43f769d445 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -971,7 +971,7 @@ out_bus: out: crw_unregister_handler(CRW_RSC_CSS); chsc_free_sei_area(); - kfree(slow_subchannel_set); + idset_free(slow_subchannel_set); pr_alert("The CSS device driver initialization failed with " "errno=%d\n", ret); return ret; @@ -993,7 +993,7 @@ static void __init css_bus_cleanup(void) bus_unregister(&css_bus_type); crw_unregister_handler(CRW_RSC_CSS); chsc_free_sei_area(); - kfree(slow_subchannel_set); + idset_free(slow_subchannel_set); isc_unregister(IO_SCH_ISC); } -- cgit v1.2.3 From b0a285d31bd475fdd4312e457288be558b705e55 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:37 +0200 Subject: [S390] cio: idset use actual number of ssids The functions idset_sch_new and for_each_subchannel_staged use different values for the number of subchannel sets. Make it consistent by changing idset_sch_new to also use the actual number of subchannel sets. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 26 +++++++++++++------------- drivers/s390/cio/css.h | 1 + drivers/s390/cio/idset.c | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index b43f769d445..5e217bbf879 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -32,7 +32,7 @@ int css_init_done = 0; static int need_reprobe = 0; -static int max_ssid = 0; +int max_ssid; struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; @@ -879,6 +879,18 @@ static int __init css_bus_init(void) if (ret) goto out; + /* Try to enable MSS. */ + ret = chsc_enable_facility(CHSC_SDA_OC_MSS); + switch (ret) { + case 0: /* Success. */ + max_ssid = __MAX_SSID; + break; + case -ENOMEM: + goto out; + default: + max_ssid = 0; + } + ret = slow_subchannel_init(); if (ret) goto out; @@ -890,17 +902,6 @@ static int __init css_bus_init(void) if ((ret = bus_register(&css_bus_type))) goto out; - /* Try to enable MSS. */ - ret = chsc_enable_facility(CHSC_SDA_OC_MSS); - switch (ret) { - case 0: /* Success. */ - max_ssid = __MAX_SSID; - break; - case -ENOMEM: - goto out_bus; - default: - max_ssid = 0; - } /* Setup css structure. */ for (i = 0; i <= __MAX_CSSID; i++) { struct channel_subsystem *css; @@ -966,7 +967,6 @@ out_unregister: &dev_attr_cm_enable); device_unregister(&css->device); } -out_bus: bus_unregister(&css_bus_type); out: crw_unregister_handler(CRW_RSC_CSS); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 54acdaade86..68d6b0bf151 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -111,6 +111,7 @@ extern void css_sch_device_unregister(struct subchannel *); extern int css_probe_device(struct subchannel_id); extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; +extern int max_ssid; int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), int (*fn_unknown)(struct subchannel_id, void *), void *data); diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 77e42cb127b..5c88faf5b89 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -78,7 +78,7 @@ static inline int idset_get_first(struct idset *set, int *ssid, int *id) struct idset *idset_sch_new(void) { - return idset_new(__MAX_SSID + 1, __MAX_SUBCHANNEL + 1); + return idset_new(max_ssid + 1, __MAX_SUBCHANNEL + 1); } void idset_sch_add(struct idset *set, struct subchannel_id schid) -- cgit v1.2.3 From 703e5c9993639284bc0a8929b6de362424df7019 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 22 Sep 2009 22:58:38 +0200 Subject: [S390] cio: introduce consistent subchannel scanning Previously, there were multiple subchannel scanning mechanisms which could potentially conflict with each other. Fix this problem by moving blacklist and ccw driver triggered scanning to the existing evaluation method. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 146 +++++++++++++---------------------------------- drivers/s390/cio/idset.c | 10 ++++ drivers/s390/cio/idset.h | 1 + 3 files changed, 51 insertions(+), 106 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5e217bbf879..91c25706fa8 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -31,7 +31,6 @@ #include "chp.h" int css_init_done = 0; -static int need_reprobe = 0; int max_ssid; struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; @@ -315,12 +314,18 @@ int css_probe_device(struct subchannel_id schid) int ret; struct subchannel *sch; - sch = css_alloc_subchannel(schid); - if (IS_ERR(sch)) - return PTR_ERR(sch); + if (cio_is_console(schid)) + sch = cio_get_console_subchannel(); + else { + sch = css_alloc_subchannel(schid); + if (IS_ERR(sch)) + return PTR_ERR(sch); + } ret = css_register_subchannel(sch); - if (ret) - put_device(&sch->dev); + if (ret) { + if (!cio_is_console(schid)) + put_device(&sch->dev); + } return ret; } @@ -510,76 +515,48 @@ void css_schedule_eval_all(void) spin_unlock_irqrestore(&slow_subchannel_lock, flags); } -void css_wait_for_slow_path(void) +static int __unset_registered(struct device *dev, void *data) { - flush_workqueue(slow_path_wq); -} - -/* Reprobe subchannel if unregistered. */ -static int reprobe_subchannel(struct subchannel_id schid, void *data) -{ - int ret; - - CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n", - schid.ssid, schid.sch_no); - if (need_reprobe) - return -EAGAIN; - - ret = css_probe_device(schid); - switch (ret) { - case 0: - break; - case -ENXIO: - case -ENOMEM: - case -EIO: - /* These should abort looping */ - break; - default: - ret = 0; - } - - return ret; -} + struct idset *set = data; + struct subchannel *sch = to_subchannel(dev); -static void reprobe_after_idle(struct work_struct *unused) -{ - /* Make sure initial subchannel scan is done. */ - wait_event(ccw_device_init_wq, - atomic_read(&ccw_device_init_count) == 0); - if (need_reprobe) - css_schedule_reprobe(); + idset_sch_del(set, sch->schid); + return 0; } -static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); - -/* Work function used to reprobe all unregistered subchannels. */ -static void reprobe_all(struct work_struct *unused) +void css_schedule_eval_all_unreg(void) { - int ret; - - CIO_MSG_EVENT(4, "reprobe start\n"); + unsigned long flags; + struct idset *unreg_set; - /* Make sure initial subchannel scan is done. */ - if (atomic_read(&ccw_device_init_count) != 0) { - queue_work(ccw_device_work, &reprobe_idle_work); + /* Find unregistered subchannels. */ + unreg_set = idset_sch_new(); + if (!unreg_set) { + /* Fallback. */ + css_schedule_eval_all(); return; } - need_reprobe = 0; - ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); - - CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, - need_reprobe); + idset_fill(unreg_set); + bus_for_each_dev(&css_bus_type, NULL, unreg_set, __unset_registered); + /* Apply to slow_subchannel_set. */ + spin_lock_irqsave(&slow_subchannel_lock, flags); + idset_add_set(slow_subchannel_set, unreg_set); + atomic_set(&css_eval_scheduled, 1); + queue_work(slow_path_wq, &slow_path_work); + spin_unlock_irqrestore(&slow_subchannel_lock, flags); + idset_free(unreg_set); } -static DECLARE_WORK(css_reprobe_work, reprobe_all); +void css_wait_for_slow_path(void) +{ + flush_workqueue(slow_path_wq); +} /* Schedule reprobing of all unregistered subchannels. */ void css_schedule_reprobe(void) { - need_reprobe = 1; - queue_work(slow_path_wq, &css_reprobe_work); + css_schedule_eval_all_unreg(); } - EXPORT_SYMBOL_GPL(css_schedule_reprobe); /* @@ -615,48 +592,6 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) css_evaluate_subchannel(mchk_schid, 0); } -static int __init setup_subchannel(struct subchannel_id schid, void *data) -{ - struct subchannel *sch; - int ret; - - if (cio_is_console(schid)) - sch = cio_get_console_subchannel(); - else { - sch = css_alloc_subchannel(schid); - if (IS_ERR(sch)) - ret = PTR_ERR(sch); - else - ret = 0; - switch (ret) { - case 0: - break; - case -ENOMEM: - panic("Out of memory in init_channel_subsystem\n"); - /* -ENXIO: no more subchannels. */ - case -ENXIO: - return ret; - /* -EIO: this subchannel set not supported. */ - case -EIO: - return ret; - default: - return 0; - } - } - /* - * We register ALL valid subchannels in ioinfo, even those - * that have been present before init_channel_subsystem. - * These subchannels can't have been registered yet (kmalloc - * not working) so we do it now. This is true e.g. for the - * console subchannel. - */ - if (css_register_subchannel(sch)) { - if (!cio_is_console(schid)) - put_device(&sch->dev); - } - return 0; -} - static void __init css_generate_pgid(struct channel_subsystem *css, u32 tod_high) { @@ -1028,11 +963,10 @@ static int css_settle(struct device_driver *drv, void *unused) */ static int __init channel_subsystem_init_sync(void) { - /* Allocate and register subchannels. */ - for_each_subchannel(setup_subchannel, NULL); + /* Start initial subchannel evaluation. */ + css_schedule_eval_all(); /* Wait for the evaluation of subchannels to finish. */ wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); - /* Wait for the subchannel type specific initialization to finish */ return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle); } diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 5c88faf5b89..4d10981c7cc 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -120,3 +120,13 @@ int idset_is_empty(struct idset *set) return 1; return 0; } + +void idset_add_set(struct idset *to, struct idset *from) +{ + unsigned long i, len; + + len = min(__BITOPS_WORDS(to->num_ssid * to->num_id), + __BITOPS_WORDS(from->num_ssid * from->num_id)); + for (i = 0; i < len ; i++) + to->bitmap[i] |= from->bitmap[i]; +} diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index ca1398aadc7..7543da4529f 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -22,5 +22,6 @@ void idset_sch_del(struct idset *set, struct subchannel_id id); int idset_sch_contains(struct idset *set, struct subchannel_id id); int idset_sch_get_first(struct idset *set, struct subchannel_id *id); int idset_is_empty(struct idset *set); +void idset_add_set(struct idset *to, struct idset *from); #endif /* S390_IDSET_H */ -- cgit v1.2.3 From 1d7e1500a6acfc89415aa2524e2c475c980ac42a Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 22 Sep 2009 22:58:39 +0200 Subject: [S390] qdio: reduce per device debug messages Even if turned off the debug message overhead is measurable in the hot path. Reduce the number of debug message calls in do_QDIO and qdio_kick_handler. Also use hex numbers to save space in the debug entries. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 9aef402a5f1..21766c791ad 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -401,7 +401,7 @@ static void announce_buffer_error(struct qdio_q *q, int count) if ((!q->is_input_q && (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { qdio_perf_stat_inc(&perf_stats.outbound_target_full); - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d", + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x", q->first_to_check); return; } @@ -418,7 +418,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) { int new; - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %02x", count); /* for QEBSM the ACK was already set by EQBS */ if (is_qebsm(q)) { @@ -545,7 +545,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) * has (probably) not moved (see qdio_inbound_processing). */ if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", q->first_to_check); return 1; } else @@ -565,11 +565,10 @@ static void qdio_kick_handler(struct qdio_q *q) if (q->is_input_q) { qdio_perf_stat_inc(&perf_stats.inbound_handler); - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); - } else { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr); - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); - } + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); + } else + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", + start, count); q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, q->irq_ptr->int_parm); @@ -633,7 +632,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) switch (state) { case SLSB_P_OUTPUT_EMPTY: /* the adapter got it */ - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %02x", q->nr, count); atomic_sub(count, &q->nr_buf_used); q->first_to_check = add_buf(q->first_to_check, count); @@ -1481,10 +1480,9 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, get_buf_state(q, prev_buf(bufnr), &state, 0); if (state != SLSB_CU_OUTPUT_PRIMED) rc = qdio_kick_outbound_q(q); - else { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); + else qdio_perf_stat_inc(&perf_stats.fast_requeue); - } + out: tasklet_schedule(&q->tasklet); return rc; @@ -1510,12 +1508,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (!irq_ptr) return -ENODEV; - if (callflags & QDIO_FLAG_SYNC_INPUT) - DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input"); - else - DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output"); - DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags); - DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, + "do%02x b:%02x c:%02x", callflags, bufnr, count); if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) return -EBUSY; -- cgit v1.2.3 From 6541f7b68f229aacd2e453bc9e94335fc56419fe Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 22 Sep 2009 22:58:40 +0200 Subject: [S390] qdio: change state of all primed input buffers If input buffers stay in primed state qdio may not receive further interrupts for the input queue depending on the firmware. That can cause a connection hang on OSA cards. Change the state of all primed input buffers that are not acknowledged to not initialized. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 21766c791ad..4be6e84b959 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -455,6 +455,8 @@ static inline void inbound_primed(struct qdio_q *q, int count) count--; if (!count) return; + /* need to change ALL buffers to get more interrupts */ + set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, count); } static int get_inbound_buffer_frontier(struct qdio_q *q) -- cgit v1.2.3 From 2d70ca23f86647e076e3a8b64b3a90e583b894d5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:41 +0200 Subject: [S390] Convert sys_clone to function with parameters. Use function parameters instead of accessing the pt_regs structure to get the parameters. Also merge the 31 and 64 bit versions since they are identical. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/compat_linux.c | 17 ----------------- arch/s390/kernel/compat_linux.h | 1 - arch/s390/kernel/compat_wrapper.S | 8 ++++++++ arch/s390/kernel/entry.h | 3 ++- arch/s390/kernel/process.c | 10 ++-------- arch/s390/kernel/syscalls.S | 2 +- 6 files changed, 13 insertions(+), 28 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 9ab188d67a3..f741cd49111 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -801,23 +801,6 @@ asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count) return sys_write(fd, buf, count); } -asmlinkage long sys32_clone(void) -{ - struct pt_regs *regs = task_pt_regs(current); - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - - clone_flags = regs->gprs[3] & 0xffffffffUL; - newsp = regs->orig_gpr2 & 0x7fffffffUL; - parent_tidptr = compat_ptr(regs->gprs[4]); - child_tidptr = compat_ptr(regs->gprs[5]); - if (!newsp) - newsp = regs->gprs[15]; - return do_fork(clone_flags, newsp, regs, 0, - parent_tidptr, child_tidptr); -} - /* * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64. * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE} diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 836a2884290..7cceb67ff8a 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -222,7 +222,6 @@ unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg); long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg); long sys32_read(unsigned int fd, char __user * buf, size_t count); long sys32_write(unsigned int fd, char __user * buf, size_t count); -long sys32_clone(void); long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise); long sys32_fadvise64_64(struct fadvise64_64_args __user *args); long sys32_sigaction(int sig, const struct old_sigaction32 __user *act, diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 624790042d4..28f8440d2ec 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1840,3 +1840,11 @@ sys_perf_event_open_wrapper: lgfr %r5,%r5 # int llgfr %r6,%r6 # unsigned long jg sys_perf_event_open # branch to system call + + .globl sys_clone_wrapper +sys_clone_wrapper: + llgfr %r2,%r2 # unsigned long + llgfr %r3,%r3 # unsigned long + llgtr %r4,%r4 # int * + llgtr %r5,%r5 # int * + jg sys_clone # branch to system call diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 950c59c6688..91fd78839c5 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -42,7 +42,8 @@ long sys_s390_fadvise64_64(struct fadvise64_64_args __user *args); long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, u32 len_low); long sys_fork(void); -long sys_clone(void); +long sys_clone(unsigned long newsp, unsigned long clone_flags, + int __user *parent_tidptr, int __user *child_tidptr); long sys_vfork(void); void execve_tail(void); long sys_execve(void); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 5a43f27eec1..189d978f76d 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -230,17 +230,11 @@ SYSCALL_DEFINE0(fork) return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); } -SYSCALL_DEFINE0(clone) +SYSCALL_DEFINE4(clone, unsigned long, newsp, unsigned long, clone_flags, + int __user *, parent_tidptr, int __user *, child_tidptr) { struct pt_regs *regs = task_pt_regs(current); - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - clone_flags = regs->gprs[3]; - newsp = regs->orig_gpr2; - parent_tidptr = (int __user *) regs->gprs[4]; - child_tidptr = (int __user *) regs->gprs[5]; if (!newsp) newsp = regs->gprs[15]; return do_fork(clone_flags, newsp, regs, 0, diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 0b5083681e7..ff79d58e0eb 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -128,7 +128,7 @@ SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) -SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */ +SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */ SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper) NI_SYSCALL /* modify_ldt for i386 */ -- cgit v1.2.3 From 3e86a8c617413e344143839c514e9b0c1713065c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:42 +0200 Subject: [S390] Convert sys_execve to function with parameters. Use function parameters instead of accessing the pt_regs structure to get the parameters. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/compat_linux.c | 33 ++++++++++++++------------------- arch/s390/kernel/compat_linux.h | 3 ++- arch/s390/kernel/compat_wrapper.S | 7 +++++++ arch/s390/kernel/entry.h | 3 ++- arch/s390/kernel/process.c | 30 +++++++++++++----------------- arch/s390/kernel/syscalls.S | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index f741cd49111..05cf446e60b 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -443,31 +443,26 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) * sys32_execve() executes a new program after the asm stub has set * things up for us. This should basically do what I want it to. */ -asmlinkage long sys32_execve(void) +asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, + compat_uptr_t __user *envp) { struct pt_regs *regs = task_pt_regs(current); char *filename; - unsigned long result; - int rc; - - filename = getname(compat_ptr(regs->orig_gpr2)); - if (IS_ERR(filename)) { - result = PTR_ERR(filename); - goto out; - } - rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]), - compat_ptr(regs->gprs[4]), regs); - if (rc) { - result = rc; - goto out_putname; - } + long rc; + + filename = getname(name); + rc = PTR_ERR(filename); + if (IS_ERR(filename)) + return rc; + rc = compat_do_execve(filename, argv, envp, regs); + if (rc) + goto out; current->thread.fp_regs.fpc=0; asm volatile("sfpc %0,0" : : "d" (0)); - result = regs->gprs[2]; -out_putname: - putname(filename); + rc = regs->gprs[2]; out: - return result; + putname(filename); + return rc; } diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 7cceb67ff8a..c07f9ca05ad 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -198,7 +198,8 @@ long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, size_t sigsetsize); long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize); long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo); -long sys32_execve(void); +long sys32_execve(char __user *name, compat_uptr_t __user *argv, + compat_uptr_t __user *envp); long sys32_init_module(void __user *umod, unsigned long len, const char __user *uargs); long sys32_delete_module(const char __user *name_user, unsigned int flags); diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 28f8440d2ec..8a6a7969c62 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1848,3 +1848,10 @@ sys_clone_wrapper: llgtr %r4,%r4 # int * llgtr %r5,%r5 # int * jg sys_clone # branch to system call + + .globl sys32_execve_wrapper +sys32_execve_wrapper: + llgtr %r2,%r2 # char * + llgtr %r3,%r3 # compat_uptr_t * + llgtr %r4,%r4 # compat_uptr_t * + jg sys32_execve # branch to system call diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 91fd78839c5..e1e5e767ab5 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -46,7 +46,8 @@ long sys_clone(unsigned long newsp, unsigned long clone_flags, int __user *parent_tidptr, int __user *child_tidptr); long sys_vfork(void); void execve_tail(void); -long sys_execve(void); +long sys_execve(char __user *name, char __user * __user *argv, + char __user * __user *envp); long sys_sigsuspend(int history0, int history1, old_sigset_t mask); long sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 189d978f76d..59fe6ecc6ed 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -268,30 +269,25 @@ asmlinkage void execve_tail(void) /* * sys_execve() executes a new program. */ -SYSCALL_DEFINE0(execve) +SYSCALL_DEFINE3(execve, char __user *, name, char __user * __user *, argv, + char __user * __user *, envp) { struct pt_regs *regs = task_pt_regs(current); char *filename; - unsigned long result; - int rc; + long rc; - filename = getname((char __user *) regs->orig_gpr2); - if (IS_ERR(filename)) { - result = PTR_ERR(filename); + filename = getname(name); + rc = PTR_ERR(filename); + if (IS_ERR(filename)) + return rc; + rc = do_execve(filename, argv, envp, regs); + if (rc) goto out; - } - rc = do_execve(filename, (char __user * __user *) regs->gprs[3], - (char __user * __user *) regs->gprs[4], regs); - if (rc) { - result = rc; - goto out_putname; - } execve_tail(); - result = regs->gprs[2]; -out_putname: - putname(filename); + rc = regs->gprs[2]; out: - return result; + putname(filename); + return rc; } /* diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index ff79d58e0eb..062dd8f9237 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -19,7 +19,7 @@ SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall) SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper) SYSCALL(sys_link,sys_link,sys32_link_wrapper) SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */ -SYSCALL(sys_execve,sys_execve,sys32_execve) +SYSCALL(sys_execve,sys_execve,sys32_execve_wrapper) SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper) SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */ SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper) -- cgit v1.2.3 From 2e50195f58ec045bc4601ec94478d957974f4aa4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:43 +0200 Subject: [S390] Get rid of init_module/delete_module compat functions. These functions aren't needed. Might be a leftover of the pre cond_syscall time. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/compat_linux.c | 33 --------------------------------- arch/s390/kernel/compat_wrapper.S | 12 ++++++------ arch/s390/kernel/syscalls.S | 4 ++-- 3 files changed, 8 insertions(+), 41 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 05cf446e60b..5519cb74510 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -465,39 +465,6 @@ out: return rc; } - -#ifdef CONFIG_MODULES - -asmlinkage long -sys32_init_module(void __user *umod, unsigned long len, - const char __user *uargs) -{ - return sys_init_module(umod, len, uargs); -} - -asmlinkage long -sys32_delete_module(const char __user *name_user, unsigned int flags) -{ - return sys_delete_module(name_user, flags); -} - -#else /* CONFIG_MODULES */ - -asmlinkage long -sys32_init_module(void __user *umod, unsigned long len, - const char __user *uargs) -{ - return -ENOSYS; -} - -asmlinkage long -sys32_delete_module(const char __user *name_user, unsigned int flags) -{ - return -ENOSYS; -} - -#endif /* CONFIG_MODULES */ - asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, u32 poshi, u32 poslo) { diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 8a6a7969c62..682fb69dba2 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -568,18 +568,18 @@ compat_sys_sigprocmask_wrapper: llgtr %r4,%r4 # compat_old_sigset_t * jg compat_sys_sigprocmask # branch to system call - .globl sys32_init_module_wrapper -sys32_init_module_wrapper: + .globl sys_init_module_wrapper +sys_init_module_wrapper: llgtr %r2,%r2 # void * llgfr %r3,%r3 # unsigned long llgtr %r4,%r4 # char * - jg sys32_init_module # branch to system call + jg sys_init_module # branch to system call - .globl sys32_delete_module_wrapper -sys32_delete_module_wrapper: + .globl sys_delete_module_wrapper +sys_delete_module_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned int - jg sys32_delete_module # branch to system call + jg sys_delete_module # branch to system call .globl sys32_quotactl_wrapper sys32_quotactl_wrapper: diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 062dd8f9237..30eca070d42 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -136,8 +136,8 @@ SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper) SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */ SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper) NI_SYSCALL /* old "create module" */ -SYSCALL(sys_init_module,sys_init_module,sys32_init_module_wrapper) -SYSCALL(sys_delete_module,sys_delete_module,sys32_delete_module_wrapper) +SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper) +SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper) NI_SYSCALL /* 130: old get_kernel_syms */ SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper) SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper) -- cgit v1.2.3 From 846955c8afe5ebca2f8841b042ca3342e08a092b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:44 +0200 Subject: [S390] hibernation: fix guest page hinting related crash On resume the system that loads the to be resumed image might have unstable pages. When the resume image is copied back and a write access happen to an unstable page this causes an exception and the system crashes. To fix this set all free pages to stable before copying the resumed image data. Also after everything has been restored set all free pages of the resumed system to unstable again. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/swsusp_asm64.S | 7 ++++++ arch/s390/mm/page-states.c | 52 ++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 7cd6b096f0d..9a86ccb91a8 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -102,6 +102,9 @@ swsusp_arch_resume: aghi %r15,-STACK_FRAME_OVERHEAD stg %r1,__SF_BACKCHAIN(%r15) + /* Make all free pages stable */ + lghi %r2,1 + brasl %r14,arch_set_page_states #ifdef CONFIG_SMP /* Save boot cpu number */ brasl %r14,smp_get_phys_cpu_id @@ -178,6 +181,10 @@ swsusp_arch_resume: /* Activate DAT */ stosm __SF_EMPTY(%r15),0x04 + /* Make all free pages unstable */ + lghi %r2,0 + brasl %r14,arch_set_page_states + /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index f92ec203ad9..098923ae458 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -50,28 +50,64 @@ void __init cmma_init(void) cmma_flag = 0; } -void arch_free_page(struct page *page, int order) +static inline void set_page_unstable(struct page *page, int order) { int i, rc; - if (!cmma_flag) - return; for (i = 0; i < (1 << order); i++) asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" : "=&d" (rc) - : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), + : "a" (page_to_phys(page + i)), "i" (ESSA_SET_UNUSED)); } -void arch_alloc_page(struct page *page, int order) +void arch_free_page(struct page *page, int order) { - int i, rc; - if (!cmma_flag) return; + set_page_unstable(page, order); +} + +static inline void set_page_stable(struct page *page, int order) +{ + int i, rc; + for (i = 0; i < (1 << order); i++) asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" : "=&d" (rc) - : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), + : "a" (page_to_phys(page + i)), "i" (ESSA_SET_STABLE)); } + +void arch_alloc_page(struct page *page, int order) +{ + if (!cmma_flag) + return; + set_page_stable(page, order); +} + +void arch_set_page_states(int make_stable) +{ + unsigned long flags, order, t; + struct list_head *l; + struct page *page; + struct zone *zone; + + if (!cmma_flag) + return; + if (make_stable) + drain_local_pages(NULL); + for_each_populated_zone(zone) { + spin_lock_irqsave(&zone->lock, flags); + for_each_migratetype_order(order, t) { + list_for_each(l, &zone->free_area[order].free_list[t]) { + page = list_entry(l, struct page, lru); + if (make_stable) + set_page_stable(page, order); + else + set_page_unstable(page, order); + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } +} -- cgit v1.2.3 From 2583d1efe04170cf166d43da6e4ed309e5601e84 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:45 +0200 Subject: [S390] hibernation: reset system after resume Force system into defined state after resume. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/swsusp_asm64.S | 42 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 9a86ccb91a8..fc056810a01 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -108,7 +108,8 @@ swsusp_arch_resume: #ifdef CONFIG_SMP /* Save boot cpu number */ brasl %r14,smp_get_phys_cpu_id - lgr %r10,%r2 + larl %r1,saved_cpu_id + st %r2,0(%r1) #endif /* Deactivate DAT */ stnsm __SF_EMPTY(%r15),0xfb @@ -136,6 +137,29 @@ swsusp_arch_resume: 2: ptlb /* flush tlb */ + /* Reset System */ + larl %r1,restart_entry + larl %r2,restart_psw + og %r1,0(%r2) + stg %r1,0(%r0) + larl %r1,saved_pgm_check_psw + mvc 0(16,%r1),__LC_PGM_NEW_PSW(%r0) + larl %r1,new_pgm_check_psw + epsw %r2,%r3 + stm %r2,%r3,0(%r1) + mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) + lghi %r0,0 + diag %r0,%r0,0x308 +restart_entry: + lhi %r1,1 + sigp %r1,%r0,0x12 + sam64 + larl %r1,new_pgm_check_psw + lpswe 0(%r1) +pgm_check_entry: + larl %r1,saved_pgm_check_psw + mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) + /* Restore registers */ lghi %r13,0x1000 /* %r1 = pointer to save arae */ @@ -171,7 +195,8 @@ swsusp_arch_resume: #ifdef CONFIG_SMP /* Switch CPUs */ - lgr %r2,%r10 /* get cpu id */ + larl %r1,saved_cpu_id + llgf %r2,0(%r1) llgf %r3,0x318(%r13) brasl %r14,smp_switch_boot_cpu_in_resume #endif @@ -189,3 +214,16 @@ swsusp_arch_resume: lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 br %r14 + + .section .data.nosave,"aw",@progbits + .align 8 +restart_psw: + .long 0x00080000,0x80000000 +new_pgm_check_psw: + .quad 0,pgm_check_entry +saved_pgm_check_psw: + .quad 0,0 +#ifdef CONFIG_SMP +saved_cpu_id: + .long 0 +#endif -- cgit v1.2.3 From 87458ff4582953d6b3bf45edeac8582849552e69 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:46 +0200 Subject: [S390] Change kernel_page_present coding style. Make the inline assembly look like all others. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/pgtable.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index c7021524707..c60bfb309ce 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -314,21 +314,18 @@ int s390_enable_sie(void) } EXPORT_SYMBOL_GPL(s390_enable_sie); -#ifdef CONFIG_DEBUG_PAGEALLOC -#ifdef CONFIG_HIBERNATION +#if defined(CONFIG_DEBUG_PAGEALLOC) && defined(CONFIG_HIBERNATION) bool kernel_page_present(struct page *page) { unsigned long addr; int cc; addr = page_to_phys(page); - asm("lra %1,0(%1)\n" - "ipm %0\n" - "srl %0,28" - :"=d"(cc),"+a"(addr)::"cc"); + asm volatile( + " lra %1,0(%1)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (cc), "+a" (addr) : : "cc"); return cc == 0; } - -#endif /* CONFIG_HIBERNATION */ -#endif /* CONFIG_DEBUG_PAGEALLOC */ - +#endif /* CONFIG_HIBERNATION && CONFIG_DEBUG_PAGEALLOC */ -- cgit v1.2.3 From bdd42b28cde0453fb8c3d9b4e4868ca2d8124806 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:47 +0200 Subject: [S390] fix disabled_wait inline assembly clobber list The disabled_wait inline assmembly also clobbers register r1, but it is missing in the clobber list. Fixes recursive Oops on panic. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index cf8eed3fa77..b4271545831 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -295,7 +295,7 @@ static inline void ATTRIB_NORET disabled_wait(unsigned long code) " oi 0x384(1),0x10\n"/* fake protection bit */ " lpswe 0(%1)" : "=m" (ctl_buf) - : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0"); + : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0", "1"); #endif /* __s390x__ */ while (1); } -- cgit v1.2.3 From 07805ac81c81634623042408ffea6bbad3160bfa Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 22 Sep 2009 22:58:48 +0200 Subject: [S390] ptrace: use common code for simple peek/poke operations arch_ptrace on s390 implements PTRACE_(PEEK|POKE)(TEXT|DATA) instead of using using ptrace_request in kernel/ptrace.c. The only reason is the 31bit addressing mode, where we have to unmask the highest bit. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ptrace.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index f3ddd7ac06c..a8738676b26 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -339,24 +339,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int copied, ret; switch (request) { - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* read word at location addr. */ - return generic_ptrace_peekdata(child, addr, data); - case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ return peek_user(child, addr, data); - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* write the word at location addr. */ - return generic_ptrace_pokedata(child, addr, data); - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ return poke_user(child, addr, data); @@ -386,8 +372,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied += sizeof(unsigned long); } return 0; + default: + /* Removing high order bit from addr (only for 31 bit). */ + addr &= PSW_ADDR_INSN; + return ptrace_request(child, request, addr, data); } - return ptrace_request(child, request, addr, data); } #ifdef CONFIG_COMPAT -- cgit v1.2.3 From 3fd26a7793fb21b88ccf1e238670b2a508fcf835 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:49 +0200 Subject: [S390] smp: introduce LC_ORDER and simplify lowcore handling Removes a couple of simple code duplications. But before I have to do this again, just simplify it. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 6 ++++++ arch/s390/kernel/smp.c | 14 ++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 6bc9426a6fb..8c5570366a0 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -189,6 +189,12 @@ union save_area { #define SAVE_AREA_BASE SAVE_AREA_BASE_S390X #endif +#ifndef __s390x__ +#define LC_ORDER 0 +#else +#define LC_ORDER 1 +#endif + struct _lowcore { #ifndef __s390x__ diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 56c16876b91..6f14734abe7 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -475,10 +475,8 @@ static int __cpuinit smp_alloc_lowcore(int cpu) { unsigned long async_stack, panic_stack; struct _lowcore *lowcore; - int lc_order; - lc_order = sizeof(long) == 8 ? 1 : 0; - lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); + lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); if (!lowcore) return -ENOMEM; async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); @@ -509,16 +507,14 @@ static int __cpuinit smp_alloc_lowcore(int cpu) out: free_page(panic_stack); free_pages(async_stack, ASYNC_ORDER); - free_pages((unsigned long) lowcore, lc_order); + free_pages((unsigned long) lowcore, LC_ORDER); return -ENOMEM; } static void smp_free_lowcore(int cpu) { struct _lowcore *lowcore; - int lc_order; - lc_order = sizeof(long) == 8 ? 1 : 0; lowcore = lowcore_ptr[cpu]; #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) @@ -528,7 +524,7 @@ static void smp_free_lowcore(int cpu) #endif free_page(lowcore->panic_stack - PAGE_SIZE); free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); - free_pages((unsigned long) lowcore, lc_order); + free_pages((unsigned long) lowcore, LC_ORDER); lowcore_ptr[cpu] = NULL; } @@ -664,7 +660,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) unsigned long async_stack, panic_stack; struct _lowcore *lowcore; unsigned int cpu; - int lc_order; smp_detect_cpus(); @@ -674,8 +669,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) print_cpu_info(); /* Reallocate current lowcore, but keep its contents. */ - lc_order = sizeof(long) == 8 ? 1 : 0; - lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); + lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); panic_stack = __get_free_page(GFP_KERNEL); async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); BUG_ON(!lowcore || !panic_stack || !async_stack); -- cgit v1.2.3 From 2573a575304c5ce4765fc88f9d09ed4dbf8d04bf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 22 Sep 2009 22:58:50 +0200 Subject: [S390] hibernate: make sure pfn_is_nosave handles lowcore pages pfn_is_nosave doesn't return the correct value for the second lowcore page if lowcore protection is enabled. Make sure it always returns the correct value. While at it simplify the whole thing. NSS special handling is done by the tprot check like it already works for DCSS as well. So remove the extra code for NSS. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 2 ++ arch/s390/kernel/suspend.c | 24 +++++++----------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 8c5570366a0..a3ff9b01bf7 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -195,6 +195,8 @@ union save_area { #define LC_ORDER 1 #endif +#define LC_PAGES (1UL << LC_ORDER) + struct _lowcore { #ifndef __s390x__ diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c index 086bee970ca..cf9e5c6d552 100644 --- a/arch/s390/kernel/suspend.c +++ b/arch/s390/kernel/suspend.c @@ -6,36 +6,26 @@ * Author(s): Hans-Joachim Picht */ -#include -#include #include -#include -#include #include -#include /* * References to section boundaries */ extern const void __nosave_begin, __nosave_end; -/* - * check if given pfn is in the 'nosave' or in the read only NSS section - */ int pfn_is_nosave(unsigned long pfn) { - unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; - unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) - >> PAGE_SHIFT; - unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; - unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); + unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); + unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end)); + /* Always save lowcore pages (LC protection might be enabled). */ + if (pfn <= LC_PAGES) + return 0; if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) return 1; - if (pfn >= stext_pfn && pfn <= eshared_pfn) { - if (ipl_info.type == IPL_TYPE_NSS) - return 1; - } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) + /* Skip memory holes and read-only pages (NSS, DCSS, ...). */ + if (tprot(PFN_PHYS(pfn))) return 1; return 0; } -- cgit v1.2.3 From 5314af693da5149c2361d290bb184cf18ee21cdd Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Tue, 22 Sep 2009 22:58:51 +0200 Subject: [S390] zcrypt: Do not add/remove devices in s/r callbacks Devices are no longer removed or added in the suspend and resume callbacks. Instead they are marked unregistered in suspend. In the resume callback the ap_scan_bus method is scheduled. The bus scan function will remove the old device and add new ones. This way all the device handling will be done in only one function. Additionaly the case where the domain might change during suspend/resume is caught. In that case the devices qid needs to re-calculated in order of having it found by the scan method. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 090b32a339c..1294876bf7b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -60,6 +60,7 @@ static int ap_device_probe(struct device *dev); static void ap_interrupt_handler(void *unused1, void *unused2); static void ap_reset(struct ap_device *ap_dev); static void ap_config_timeout(unsigned long ptr); +static int ap_select_domain(void); /* * Module description. @@ -109,6 +110,10 @@ static unsigned long long poll_timeout = 250000; /* Suspend flag */ static int ap_suspend_flag; +/* Flag to check if domain was set through module parameter domain=. This is + * important when supsend and resume is done in a z/VM environment where the + * domain might change. */ +static int user_set_domain = 0; static struct bus_type ap_bus_type; /** @@ -643,6 +648,7 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) destroy_workqueue(ap_work_queue); ap_work_queue = NULL; } + tasklet_disable(&ap_tasklet); } /* Poll on the device until all requests are finished. */ @@ -653,7 +659,10 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) spin_unlock_bh(&ap_dev->lock); } while ((flags & 1) || (flags & 2)); - ap_device_remove(dev); + spin_lock_bh(&ap_dev->lock); + ap_dev->unregistered = 1; + spin_unlock_bh(&ap_dev->lock); + return 0; } @@ -666,11 +675,10 @@ static int ap_bus_resume(struct device *dev) ap_suspend_flag = 0; if (!ap_interrupts_available()) ap_interrupt_indicator = NULL; - ap_device_probe(dev); - ap_reset(ap_dev); - setup_timer(&ap_dev->timeout, ap_request_timeout, - (unsigned long) ap_dev); - ap_scan_bus(NULL); + if (!user_set_domain) { + ap_domain_index = -1; + ap_select_domain(); + } init_timer(&ap_config_timer); ap_config_timer.function = ap_config_timeout; ap_config_timer.data = 0; @@ -686,12 +694,14 @@ static int ap_bus_resume(struct device *dev) tasklet_schedule(&ap_tasklet); if (ap_thread_flag) rc = ap_poll_thread_start(); - } else { - ap_device_probe(dev); - ap_reset(ap_dev); - setup_timer(&ap_dev->timeout, ap_request_timeout, - (unsigned long) ap_dev); } + if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { + spin_lock_bh(&ap_dev->lock); + ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), + ap_domain_index); + spin_unlock_bh(&ap_dev->lock); + } + queue_work(ap_work_queue, &ap_config_work); return rc; } @@ -1079,6 +1089,8 @@ static void ap_scan_bus(struct work_struct *unused) spin_lock_bh(&ap_dev->lock); if (rc || ap_dev->unregistered) { spin_unlock_bh(&ap_dev->lock); + if (ap_dev->unregistered) + i--; device_unregister(dev); put_device(dev); continue; @@ -1586,6 +1598,12 @@ int __init ap_module_init(void) ap_domain_index); return -EINVAL; } + /* In resume callback we need to know if the user had set the domain. + * If so, we can not just reset it. + */ + if (ap_domain_index >= 0) + user_set_domain = 1; + if (ap_instructions_available() != 0) { pr_warning("The hardware system does not support " "AP instructions\n"); -- cgit v1.2.3 From 68d1e5f08b13132504752cad54169376739753db Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Tue, 22 Sep 2009 22:58:52 +0200 Subject: [S390] dasd: tolerate devices that have no feature codes The DASD device driver reads the feature codes of a device during device initialization. These codes are later used to determine the availability of advanced features like PAV or High Performance FICON. Some very old devices do not support the command to read feature codes and the initialization routine fails. As the feature codes are not necessary for basic DASD operations, we can support such devices by just ignoring missing feature codes. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a1ce573648a..614813f692e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -935,6 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) struct dasd_eckd_private *private; private = (struct dasd_eckd_private *) device->private; + memset(&private->features, 0, sizeof(struct dasd_rssd_features)); cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data) + sizeof(struct dasd_rssd_features)), @@ -982,7 +983,9 @@ static int dasd_eckd_read_features(struct dasd_device *device) features = (struct dasd_rssd_features *) (prssdp + 1); memcpy(&private->features, features, sizeof(struct dasd_rssd_features)); - } + } else + dev_warn(&device->cdev->dev, "Reading device feature codes" + " failed with rc=%d\n", rc); dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1144,9 +1147,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) } /* Read Feature Codes */ - rc = dasd_eckd_read_features(device); - if (rc) - goto out_err3; + dasd_eckd_read_features(device); /* Read Device Characteristics */ rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, @@ -3241,9 +3242,7 @@ int dasd_eckd_restore_device(struct dasd_device *device) } /* Read Feature Codes */ - rc = dasd_eckd_read_features(device); - if (rc) - goto out_err; + dasd_eckd_read_features(device); /* Read Device Characteristics */ memset(&private->rdc_data, 0, sizeof(private->rdc_data)); -- cgit v1.2.3 From 1aaf179d043856d80bbb354f9feaf706b9cfbcd3 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 22 Sep 2009 22:58:53 +0200 Subject: [S390] hibernate: Do real CPU swap at resume time Currently, when the physical resume CPU is not equal to the physical suspend CPU, we swap the CPUs logically, by modifying the logical/physical CPU mapping. This has two major drawbacks: First the change is visible from user space (e.g. CPU sysfs files) and second it is hard to ensure that nowhere in the kernel the physical CPU ID is stored before suspend. To fix this, we now really swap the physical CPUs, if the resume CPU is not the pysical suspend CPU. We restart the suspend CPU and stop the resume CPU using SIGP restart and SIGP stop. If the suspend CPU is no longer available, we write a message and load a disabled wait PSW. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/lowcore.h | 1 + arch/s390/kernel/asm-offsets.c | 7 +++- arch/s390/kernel/sclp.S | 5 +-- arch/s390/kernel/smp.c | 36 ---------------- arch/s390/kernel/swsusp_asm64.S | 91 ++++++++++++++++++++++++++++------------- 5 files changed, 71 insertions(+), 69 deletions(-) diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index a3ff9b01bf7..f2ef4b619ce 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -86,6 +86,7 @@ #define __LC_PGM_OLD_PSW 0x0150 #define __LC_MCK_OLD_PSW 0x0160 #define __LC_IO_OLD_PSW 0x0170 +#define __LC_RESTART_PSW 0x01a0 #define __LC_EXT_NEW_PSW 0x01b0 #define __LC_SVC_NEW_PSW 0x01c0 #define __LC_PGM_NEW_PSW 0x01d0 diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index fa9905ce7d0..63e46433e81 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -7,6 +7,7 @@ #include #include #include +#include int main(void) { @@ -59,6 +60,10 @@ int main(void) DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); - + /* constants for SIGP */ + DEFINE(__SIGP_STOP, sigp_stop); + DEFINE(__SIGP_RESTART, sigp_restart); + DEFINE(__SIGP_SENSE, sigp_sense); + DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset); return 0; } diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index 20639dfe0c4..e27ca63076d 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S @@ -24,8 +24,6 @@ LC_EXT_INT_CODE = 0x86 # addr of ext int code # R3 = external interruption parameter if R2=0 # -.section ".init.text","ax" - _sclp_wait_int: stm %r6,%r15,24(%r15) # save registers basr %r13,0 # get base register @@ -318,9 +316,8 @@ _sclp_print_early: .long _sclp_work_area .Lascebc: .long _ascebc -.previous -.section ".init.data","a" +.section .data,"aw",@progbits .balign 4096 _sclp_work_area: .fill 4096 diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 6f14734abe7..b4b6396e6cf 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1041,42 +1041,6 @@ out: static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, dispatching_store); -/* - * If the resume kernel runs on another cpu than the suspended kernel, - * we have to switch the cpu IDs in the logical map. - */ -void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id, - struct _lowcore *suspend_lowcore) -{ - int cpu, suspend_cpu_id, resume_cpu_id; - u32 suspend_phys_cpu_id; - - suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr]; - suspend_cpu_id = suspend_lowcore->cpu_nr; - - for_each_present_cpu(cpu) { - if (__cpu_logical_map[cpu] == resume_phys_cpu_id) { - resume_cpu_id = cpu; - goto found; - } - } - panic("Could not find resume cpu in logical map.\n"); - -found: - printk("Resume cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id); - printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id); - - __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id; - __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id; - - lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id; -} - -u32 smp_get_phys_cpu_id(void) -{ - return __cpu_logical_map[smp_processor_id()]; -} - static int __init topology_init(void) { int cpu; diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index fc056810a01..fe927d0bc20 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -9,6 +9,7 @@ #include #include +#include #include /* @@ -41,6 +42,9 @@ swsusp_arch_suspend: /* Get pointer to save area */ lghi %r1,0x1000 + /* Save CPU address */ + stap __LC_CPU_ADDRESS(%r1) + /* Store registers */ mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ stfpc 0x31c(%r1) /* store fpu control */ @@ -105,12 +109,7 @@ swsusp_arch_resume: /* Make all free pages stable */ lghi %r2,1 brasl %r14,arch_set_page_states -#ifdef CONFIG_SMP - /* Save boot cpu number */ - brasl %r14,smp_get_phys_cpu_id - larl %r1,saved_cpu_id - st %r2,0(%r1) -#endif + /* Deactivate DAT */ stnsm __SF_EMPTY(%r15),0xfb @@ -139,12 +138,10 @@ swsusp_arch_resume: /* Reset System */ larl %r1,restart_entry - larl %r2,restart_psw + larl %r2,.Lrestart_diag308_psw og %r1,0(%r2) stg %r1,0(%r0) - larl %r1,saved_pgm_check_psw - mvc 0(16,%r1),__LC_PGM_NEW_PSW(%r0) - larl %r1,new_pgm_check_psw + larl %r1,.Lnew_pgm_check_psw epsw %r2,%r3 stm %r2,%r3,0(%r1) mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) @@ -154,12 +151,54 @@ restart_entry: lhi %r1,1 sigp %r1,%r0,0x12 sam64 - larl %r1,new_pgm_check_psw + larl %r1,.Lnew_pgm_check_psw lpswe 0(%r1) pgm_check_entry: - larl %r1,saved_pgm_check_psw - mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) + /* Switch to original suspend CPU */ + larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ + stap 0(%r1) + llgh %r2,0(%r1) + lghi %r3,0x1000 + llgh %r1,__LC_CPU_ADDRESS(%r3) /* Suspend CPU address: r1 */ + cgr %r1,%r2 + je restore_registers /* r1 = r2 -> nothing to do */ + larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ + mvc __LC_RESTART_PSW(16,%r0),0(%r4) +3: + sigp %r9,%r1,__SIGP_INITIAL_CPU_RESET + brc 8,4f /* accepted */ + brc 2,3b /* busy, try again */ + + /* Suspend CPU not available -> panic */ + larl %r15,init_thread_union + ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) + larl %r2,.Lpanic_string + larl %r3,_sclp_print_early + lghi %r1,0 + sam31 + sigp %r1,%r0,0x12 + basr %r14,%r3 + larl %r3,.Ldisabled_wait_31 + lpsw 0(%r3) +4: + /* Switch to suspend CPU */ + sigp %r9,%r1,__SIGP_RESTART /* start suspend CPU */ + brc 2,4b /* busy, try again */ +5: + sigp %r9,%r2,__SIGP_STOP /* stop resume (current) CPU */ +6: j 6b + +restart_suspend: + larl %r1,.Lresume_cpu + llgh %r2,0(%r1) +7: + sigp %r9,%r2,__SIGP_SENSE /* Wait for resume CPU */ + brc 2,7b /* busy, try again */ + tmll %r9,0x40 /* Test if resume CPU is stopped */ + jz 7b + +restore_registers: /* Restore registers */ lghi %r13,0x1000 /* %r1 = pointer to save arae */ @@ -193,13 +232,6 @@ pgm_check_entry: /* Pointer to save area */ lghi %r13,0x1000 -#ifdef CONFIG_SMP - /* Switch CPUs */ - larl %r1,saved_cpu_id - llgf %r2,0(%r1) - llgf %r3,0x318(%r13) - brasl %r14,smp_switch_boot_cpu_in_resume -#endif /* Restore prefix register */ spx 0x318(%r13) @@ -217,13 +249,16 @@ pgm_check_entry: .section .data.nosave,"aw",@progbits .align 8 -restart_psw: +.Ldisabled_wait_31: + .long 0x000a0000,0x00000000 +.Lpanic_string: + .asciz "Resume not possible because suspend CPU is no longer available" + .align 8 +.Lrestart_diag308_psw: .long 0x00080000,0x80000000 -new_pgm_check_psw: +.Lrestart_suspend_psw: + .quad 0x0000000180000000,restart_suspend +.Lnew_pgm_check_psw: .quad 0,pgm_check_entry -saved_pgm_check_psw: - .quad 0,0 -#ifdef CONFIG_SMP -saved_cpu_id: - .long 0 -#endif +.Lresume_cpu: + .byte 0,0 -- cgit v1.2.3 From ed87b27e00d2ca240f62f3903583a2f1541fb9ef Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 22 Sep 2009 22:58:54 +0200 Subject: [S390] Update default configuration. Signed-off-by: Martin Schwidefsky --- arch/s390/defconfig | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 4e91a2573cc..ab4464486b7 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30 -# Mon Jun 22 11:08:16 2009 +# Linux kernel version: 2.6.31 +# Tue Sep 22 17:43:13 2009 # CONFIG_SCHED_MC=y CONFIG_MMU=y @@ -24,6 +24,7 @@ CONFIG_PGSTE=y CONFIG_VIRT_CPU_ACCOUNTING=y CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y CONFIG_S390=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_CONSTRUCTORS=y @@ -48,11 +49,12 @@ CONFIG_AUDIT=y # # RCU Subsystem # -CONFIG_CLASSIC_RCU=y -# CONFIG_TREE_RCU is not set -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=64 +# CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set -# CONFIG_PREEMPT_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=17 @@ -103,11 +105,12 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y -CONFIG_HAVE_PERF_COUNTERS=y +CONFIG_HAVE_PERF_EVENTS=y # -# Performance Counters +# Kernel Performance Events And Counters # +# CONFIG_PERF_EVENTS is not set # CONFIG_PERF_COUNTERS is not set CONFIG_VM_EVENT_COUNTERS=y # CONFIG_STRIP_ASM_SYMS is not set @@ -116,7 +119,6 @@ CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set # CONFIG_PROFILING is not set -# CONFIG_MARKERS is not set CONFIG_HAVE_OPROFILE=y CONFIG_KPROBES=y CONFIG_HAVE_SYSCALL_WRAPPERS=y @@ -176,6 +178,7 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_64BIT=y +# CONFIG_KTIME_SCALAR is not set CONFIG_SMP=y CONFIG_NR_CPUS=32 CONFIG_HOTPLUG_CPU=y @@ -257,7 +260,6 @@ CONFIG_FORCE_MAX_ZONEORDER=9 CONFIG_PFAULT=y # CONFIG_SHARED_KERNEL is not set # CONFIG_CMM is not set -# CONFIG_PAGE_STATES is not set # CONFIG_APPLDATA_BASE is not set CONFIG_HZ_100=y # CONFIG_HZ_250 is not set @@ -280,6 +282,7 @@ CONFIG_PM_SLEEP_SMP=y CONFIG_PM_SLEEP=y CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="" +# CONFIG_PM_RUNTIME is not set CONFIG_NET=y # @@ -394,6 +397,7 @@ CONFIG_IP_SCTP=m # CONFIG_SCTP_HMAC_NONE is not set # CONFIG_SCTP_HMAC_SHA1 is not set CONFIG_SCTP_HMAC_MD5=y +# CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -487,6 +491,7 @@ CONFIG_CCW=y # Generic Driver Options # CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y @@ -501,6 +506,7 @@ CONFIG_BLK_DEV=y CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_OSD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -594,8 +600,11 @@ CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_SNAPSHOT=y CONFIG_DM_MIRROR=y +# CONFIG_DM_LOG_USERSPACE is not set CONFIG_DM_ZERO=y CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_QL is not set +# CONFIG_DM_MULTIPATH_ST is not set # CONFIG_DM_DELAY is not set # CONFIG_DM_UEVENT is not set CONFIG_NETDEVICES=y @@ -615,7 +624,6 @@ CONFIG_NET_ETHERNET=y # CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set -# CONFIG_KS8842 is not set CONFIG_NETDEV_1000=y CONFIG_NETDEV_10000=y # CONFIG_TR is not set @@ -678,6 +686,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_SCLP_CPI=m +CONFIG_SCLP_ASYNC=m CONFIG_S390_TAPE=m # @@ -737,6 +746,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y @@ -798,7 +808,6 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_EXOFS_FS is not set -# CONFIG_NILFS2_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y @@ -885,11 +894,13 @@ CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_LIST is not set # CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_KPROBES_SANITY_TEST is not set # CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set @@ -979,11 +990,13 @@ CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_HMAC=m # CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_VMAC=m # # Digest # CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_GHASH=m # CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=m # CONFIG_CRYPTO_MICHAEL_MIC is not set -- cgit v1.2.3