From e3850ecfc17ea8e23c02368a24fc23be129fb3b0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Dec 2016 13:45:07 +0100 Subject: s390/cpumf: get rid of variable length array The stcctm5 inline assembly uses a variable length array to specify the memory that is written to. According to the gcc manual this trick only works if the length is known at compile time. This is not the the case for the stccm5 inline assembly. Therefore simply use a full memory clobber. As requested by Martin also move the output Q constraint operand to the input operands list, since all we want is that the compiler generates an instruction that may use the displacement field: in other words we only need the address of *val. That the inline assembly actually writes to an array starting at val is taken care of with the memory clobber. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cpu_mf.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 428c41239a49..d1e0707310fd 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -199,14 +199,15 @@ static inline int ecctr(u64 ctr, u64 *val) /* Store CPU counter multiple for the MT utilization counter set */ static inline int stcctm5(u64 num, u64 *val) { - typedef struct { u64 _[num]; } addrtype; int cc; asm volatile ( " .insn rsy,0xeb0000000017,%2,5,%1\n" " ipm %0\n" " srl %0,28\n" - : "=d" (cc), "=Q" (*(addrtype *) val) : "d" (num) : "cc"); + : "=d" (cc) + : "Q" (*val), "d" (num) + : "cc", "memory"); return cc; } -- cgit v1.2.3-59-g8ed1b From 551f413434737a2a570af4555b4139898568ed57 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 15 Dec 2016 08:35:10 +0100 Subject: s390/lib: improve memmove, memset and memcpy Improve the memmove implementation to save one instruction and use better label names. Also use better label names for the memset and memcpy implementations so everything looks consistent. Suggested-by: Jens Remus Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/lib/mem.S | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index 7422a706f310..7ff79a4ff00c 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -14,31 +14,29 @@ ENTRY(memmove) ltgr %r4,%r4 lgr %r1,%r2 bzr %r14 + aghi %r4,-1 clgr %r2,%r3 jnh .Lmemmove_forward - la %r5,0(%r4,%r3) + la %r5,1(%r4,%r3) clgr %r2,%r5 jl .Lmemmove_reverse .Lmemmove_forward: - aghi %r4,-1 srlg %r0,%r4,8 ltgr %r0,%r0 - jz .Lmemmove_rest -.Lmemmove_loop: + jz .Lmemmove_forward_remainder +.Lmemmove_forward_loop: mvc 0(256,%r1),0(%r3) la %r1,256(%r1) la %r3,256(%r3) - brctg %r0,.Lmemmove_loop -.Lmemmove_rest: + brctg %r0,.Lmemmove_forward_loop +.Lmemmove_forward_remainder: larl %r5,.Lmemmove_mvc ex %r4,0(%r5) br %r14 .Lmemmove_reverse: - aghi %r4,-1 -.Lmemmove_reverse_loop: ic %r0,0(%r4,%r3) stc %r0,0(%r4,%r1) - brctg %r4,.Lmemmove_reverse_loop + brctg %r4,.Lmemmove_reverse ic %r0,0(%r4,%r3) stc %r0,0(%r4,%r1) br %r14 @@ -70,12 +68,12 @@ ENTRY(memset) srlg %r3,%r4,8 ltgr %r3,%r3 lgr %r1,%r2 - jz .Lmemset_clear_rest + jz .Lmemset_clear_remainder .Lmemset_clear_loop: xc 0(256,%r1),0(%r1) la %r1,256(%r1) brctg %r3,.Lmemset_clear_loop -.Lmemset_clear_rest: +.Lmemset_clear_remainder: larl %r3,.Lmemset_xc ex %r4,0(%r3) br %r14 @@ -87,12 +85,12 @@ ENTRY(memset) aghi %r4,-2 srlg %r3,%r4,8 ltgr %r3,%r3 - jz .Lmemset_fill_rest + jz .Lmemset_fill_remainder .Lmemset_fill_loop: mvc 1(256,%r1),0(%r1) la %r1,256(%r1) brctg %r3,.Lmemset_fill_loop -.Lmemset_fill_rest: +.Lmemset_fill_remainder: larl %r3,.Lmemset_mvc ex %r4,0(%r3) br %r14 @@ -115,7 +113,7 @@ ENTRY(memcpy) ltgr %r5,%r5 lgr %r1,%r2 jnz .Lmemcpy_loop -.Lmemcpy_rest: +.Lmemcpy_remainder: larl %r5,.Lmemcpy_mvc ex %r4,0(%r5) br %r14 @@ -124,7 +122,7 @@ ENTRY(memcpy) la %r1,256(%r1) la %r3,256(%r3) brctg %r5,.Lmemcpy_loop - j .Lmemcpy_rest + j .Lmemcpy_remainder .Lmemcpy_mvc: mvc 0(1,%r1),0(%r3) EXPORT_SYMBOL(memcpy) -- cgit v1.2.3-59-g8ed1b From 9fbd5a0931ed879f9f0a9768086da90aed6328e8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 15 Dec 2016 11:05:13 +0100 Subject: s390/cio: get rid of variable length array Use a flexible array instead. The size of the structure is not used within chsc_sstpi, therefore no change in semantics but one less sparse warning: drivers/s390/cio/chsc.c:1219:27: warning: Variable length array is used. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 11674698b36d..928d11454b7e 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1216,7 +1216,7 @@ int chsc_sstpi(void *page, void *result, size_t size) struct chsc_header request; unsigned int rsvd0[3]; struct chsc_header response; - char data[size]; + char data[]; } __attribute__ ((packed)) *rr; int rc; -- cgit v1.2.3-59-g8ed1b From 227374b1dd08cc052f36768a97a6e3ce628318fc Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 15 Dec 2016 11:28:52 +0100 Subject: s390/zcrypt: make structures static Get rid of these: drivers/s390/crypto/ap_card.c:140:20: warning: symbol 'ap_card_type' was not declared. Should it be static? drivers/s390/crypto/ap_queue.c:567:20: warning: symbol 'ap_queue_type' was not declared. Should it be static? Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_card.c | 2 +- drivers/s390/crypto/ap_queue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 0110d44172a3..1cd9128593e4 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -137,7 +137,7 @@ static const struct attribute_group *ap_card_dev_attr_groups[] = { NULL }; -struct device_type ap_card_type = { +static struct device_type ap_card_type = { .name = "ap_card", .groups = ap_card_dev_attr_groups, }; diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index b58a917dc510..7be67fa9f224 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -564,7 +564,7 @@ static const struct attribute_group *ap_queue_dev_attr_groups[] = { NULL }; -struct device_type ap_queue_type = { +static struct device_type ap_queue_type = { .name = "ap_queue", .groups = ap_queue_dev_attr_groups, }; -- cgit v1.2.3-59-g8ed1b From 57c52ae75774c717eb7cd777b5438244ae6b380c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 15 Dec 2016 12:15:17 +0100 Subject: s390/zcrypt: get rid of variable length arrays The variable length arrays used to specify clobbered memory within ap_nqap and ap_dqap would only work if the length would be known at compile time. This is not the case for both usages. Therefore simply use a full memory clobber and get rid of the old construct. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_asm.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h index 7a630047c372..287b4ad0999e 100644 --- a/drivers/s390/crypto/ap_asm.h +++ b/drivers/s390/crypto/ap_asm.h @@ -129,7 +129,6 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) { - struct msgblock { char _[length]; }; register unsigned long reg0 asm ("0") = qid | 0x40000000UL; register struct ap_queue_status reg1 asm ("1"); register unsigned long reg2 asm ("2") = (unsigned long) msg; @@ -141,8 +140,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, "0: .long 0xb2ad0042\n" /* NQAP */ " brc 2,0b" : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) - : "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg) - : "cc"); + : "d" (reg4), "d" (reg5) + : "cc", "memory"); return reg1; } @@ -168,7 +167,6 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) { - struct msgblock { char _[length]; }; register unsigned long reg0 asm("0") = qid | 0x80000000UL; register struct ap_queue_status reg1 asm ("1"); register unsigned long reg2 asm("2") = 0UL; @@ -182,8 +180,8 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, "0: .long 0xb2ae0064\n" /* DQAP */ " brc 6,0b\n" : "+d" (reg0), "=d" (reg1), "+d" (reg2), - "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), - "=m" (*(struct msgblock *) msg) : : "cc"); + "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7) + : : "cc", "memory"); *psmid = (((unsigned long long) reg6) << 32) + reg7; return reg1; } -- cgit v1.2.3-59-g8ed1b From 98cc43ab6bc9574ec4dbc61acccfdcbbfa34d4c5 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 8 Nov 2016 14:28:03 +0100 Subject: s390/cio: clarify cssid usage Currently the cssid in various structures is used as the id of the respective channel subsystem. Sometimes however we call the index in the channel_subsystems array cssid. In some places the id is even used as the index. Provide a new define MAX_CSS_IDX and use it where appropriate. In addition to that provide a dummy function to find a channel subsystem by its id and a macro to iterate over the channel subsystems. Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 13 +++++++------ drivers/s390/cio/chp.h | 2 +- drivers/s390/cio/css.c | 30 +++++++++++------------------- drivers/s390/cio/css.h | 10 ++++++++++ 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 876c7e6e3a99..7e0d4f724dda 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -444,6 +444,7 @@ int chp_update_desc(struct channel_path *chp) */ int chp_new(struct chp_id chpid) { + struct channel_subsystem *css = css_by_id(chpid.cssid); struct channel_path *chp; int ret; @@ -456,7 +457,7 @@ int chp_new(struct chp_id chpid) /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; - chp->dev.parent = &channel_subsystems[chpid.cssid]->device; + chp->dev.parent = &css->device; chp->dev.groups = chp_attr_groups; chp->dev.release = chp_release; mutex_init(&chp->lock); @@ -479,17 +480,17 @@ int chp_new(struct chp_id chpid) put_device(&chp->dev); goto out; } - mutex_lock(&channel_subsystems[chpid.cssid]->mutex); - if (channel_subsystems[chpid.cssid]->cm_enabled) { + mutex_lock(&css->mutex); + if (css->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { device_unregister(&chp->dev); - mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); + mutex_unlock(&css->mutex); goto out; } } - channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); + css->chps[chpid.id] = chp; + mutex_unlock(&css->mutex); goto out; out_free: kfree(chp); diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index bb5a68226cda..0d8437b7ea72 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -54,7 +54,7 @@ struct channel_path { /* Return channel_path struct for given chpid. */ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) { - return channel_subsystems[chpid.cssid]->chps[chpid.id]; + return css_by_id(chpid.cssid)->chps[chpid.id]; } int chp_get_status(struct chp_id chpid); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index bc099b61394d..065c4e1d4cf4 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -36,7 +36,8 @@ int css_init_done = 0; int max_ssid; -struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; +#define MAX_CSS_IDX 0 +struct channel_subsystem *channel_subsystems[MAX_CSS_IDX + 1]; static struct bus_type css_bus_type; int @@ -805,13 +806,11 @@ static int css_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) { - int ret, i; + struct channel_subsystem *css; + int ret; ret = NOTIFY_DONE; - for (i = 0; i <= __MAX_CSSID; i++) { - struct channel_subsystem *css; - - css = channel_subsystems[i]; + for_each_css(css) { mutex_lock(&css->mutex); if (css->cm_enabled) if (chsc_secm(css, 0)) @@ -835,16 +834,14 @@ static struct notifier_block css_reboot_notifier = { static int css_power_event(struct notifier_block *this, unsigned long event, void *ptr) { - int ret, i; + struct channel_subsystem *css; + int ret; switch (event) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: ret = NOTIFY_DONE; - for (i = 0; i <= __MAX_CSSID; i++) { - struct channel_subsystem *css; - - css = channel_subsystems[i]; + for_each_css(css) { mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); @@ -858,10 +855,7 @@ static int css_power_event(struct notifier_block *this, unsigned long event, case PM_POST_HIBERNATION: case PM_POST_SUSPEND: ret = NOTIFY_DONE; - for (i = 0; i <= __MAX_CSSID; i++) { - struct channel_subsystem *css; - - css = channel_subsystems[i]; + for_each_css(css) { mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); @@ -916,7 +910,7 @@ static int __init css_bus_init(void) goto out; /* Setup css structure. */ - for (i = 0; i <= __MAX_CSSID; i++) { + for (i = 0; i <= MAX_CSS_IDX; i++) { struct channel_subsystem *css; css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); @@ -993,10 +987,8 @@ out: static void __init css_bus_cleanup(void) { struct channel_subsystem *css; - int i; - for (i = 0; i <= __MAX_CSSID; i++) { - css = channel_subsystems[i]; + for_each_css(css) { device_unregister(&css->pseudo_subchannel->dev); css->pseudo_subchannel = NULL; if (css_chsc_characteristics.secm) diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 2c9107e20251..cd19c08b93b2 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -130,6 +130,16 @@ struct channel_subsystem { extern struct channel_subsystem *channel_subsystems[]; +/* Dummy helper which needs to change once we support more than one css. */ +static inline struct channel_subsystem *css_by_id(u8 cssid) +{ + return channel_subsystems[0]; +} + +/* Dummy iterator which needs to change once we support more than one css. */ +#define for_each_css(css) \ + for ((css) = channel_subsystems[0]; (css); (css) = NULL) + /* Helper functions to build lists for the slow path. */ void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval_all(void); -- cgit v1.2.3-59-g8ed1b From e2e0de9b579d4772c2b86e6c9517723ad1e2b22a Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 17 Jun 2016 19:45:23 +0200 Subject: s390/cio: use cssid for pgid generation Obtain the real channel subsystem id and use that for the generation of a unique path group id. Note that this change does not affect the channel subsystem id as used in the user-visible naming of subchannels and friends. Signed-off-by: Sebastian Ott Reviewed-by: Dong Jia Shi Reviewed-by: Peter Oberparleiter Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/cio/chsc.h | 2 ++ drivers/s390/cio/css.c | 6 ++++-- drivers/s390/cio/css.h | 2 +- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 928d11454b7e..7b0b295b2313 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1131,6 +1131,52 @@ int chsc_enable_facility(int operation_code) return ret; } +int __init chsc_get_cssid(int idx) +{ + struct { + struct chsc_header request; + u8 atype; + u32 : 24; + u32 reserved1[6]; + struct chsc_header response; + u32 reserved2[3]; + struct { + u8 cssid; + u32 : 24; + } list[0]; + } __packed *sdcal_area; + int ret; + + spin_lock_irq(&chsc_page_lock); + memset(chsc_page, 0, PAGE_SIZE); + sdcal_area = chsc_page; + sdcal_area->request.length = 0x0020; + sdcal_area->request.code = 0x0034; + sdcal_area->atype = 4; + + ret = chsc(sdcal_area); + if (ret) { + ret = (ret == 3) ? -ENODEV : -EBUSY; + goto exit; + } + + ret = chsc_error_from_response(sdcal_area->response.code); + if (ret) { + CIO_CRW_EVENT(2, "chsc: sdcal failed (rc=%04x)\n", + sdcal_area->response.code); + goto exit; + } + + if ((addr_t) &sdcal_area->list[idx] < + (addr_t) &sdcal_area->response + sdcal_area->response.length) + ret = sdcal_area->list[idx].cssid; + else + ret = -ENODEV; +exit: + spin_unlock_irq(&chsc_page_lock); + return ret; +} + struct css_general_char css_general_characteristics; struct css_chsc_char css_chsc_characteristics; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 67c87b6e63ec..321a3f765810 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -242,6 +242,8 @@ int chsc_pnso_brinfo(struct subchannel_id schid, struct chsc_brinfo_resume_token resume_token, int cnc); +int __init chsc_get_cssid(int idx); + #ifdef CONFIG_SCM_BUS int scm_update_information(void); int scm_process_availability_information(void); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 065c4e1d4cf4..13fea905c61a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -703,7 +703,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) if (css_general_characteristics.mcss) { css->global_pgid.pgid_high.ext_cssid.version = 0x80; - css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; + css->global_pgid.pgid_high.ext_cssid.cssid = + (css->cssid < 0) ? 0 : css->cssid; } else { css->global_pgid.pgid_high.cpu_addr = stap(); } @@ -794,7 +795,8 @@ static int __init setup_css(int nr) } mutex_init(&css->mutex); css->valid = 1; - css->cssid = nr; + css->cssid = chsc_get_cssid(nr); + dev_set_name(&css->device, "css%x", nr); css->device.release = channel_subsystem_release; tod_high = (u32) (get_tod_clock() >> 32); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index cd19c08b93b2..3056f96f9d82 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -113,7 +113,7 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); void css_update_ssd_info(struct subchannel *sch); struct channel_subsystem { - u8 cssid; + int cssid; int valid; struct channel_path *chps[__MAX_CHPID + 1]; struct device device; -- cgit v1.2.3-59-g8ed1b From 6c7012688bdc8c9349dc8f289d2da2dacba3928d Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 11 Oct 2016 16:37:43 +0200 Subject: s390/cio: css attribute cleanup Cleanup the code to handle the css device attribute. Move everything to an attribute group to let the driver core handle attribute creation and removal. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 57 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 13fea905c61a..59bd441b1cd3 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -729,28 +729,24 @@ channel_subsystem_release(struct device *dev) kfree(css); } -static ssize_t -css_cm_enable_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a, + char *buf) { struct channel_subsystem *css = to_css(dev); int ret; - if (!css) - return 0; mutex_lock(&css->mutex); ret = sprintf(buf, "%x\n", css->cm_enabled); mutex_unlock(&css->mutex); return ret; } -static ssize_t -css_cm_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t cm_enable_store(struct device *dev, struct device_attribute *a, + const char *buf, size_t count) { struct channel_subsystem *css = to_css(dev); - int ret; unsigned long val; + int ret; ret = kstrtoul(buf, 16, &val); if (ret) @@ -769,8 +765,28 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, mutex_unlock(&css->mutex); return ret < 0 ? ret : count; } +static DEVICE_ATTR_RW(cm_enable); + +static umode_t cm_enable_mode(struct kobject *kobj, struct attribute *attr, + int index) +{ + return css_chsc_characteristics.secm ? attr->mode : 0; +} + +static struct attribute *cssdev_cm_attrs[] = { + &dev_attr_cm_enable.attr, + NULL, +}; + +static struct attribute_group cssdev_cm_attr_group = { + .attrs = cssdev_cm_attrs, + .is_visible = cm_enable_mode, +}; -static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); +static const struct attribute_group *cssdev_attr_groups[] = { + &cssdev_cm_attr_group, + NULL, +}; static int __init setup_css(int nr) { @@ -798,6 +814,7 @@ static int __init setup_css(int nr) css->cssid = chsc_get_cssid(nr); dev_set_name(&css->device, "css%x", nr); + css->device.groups = cssdev_attr_groups; css->device.release = channel_subsystem_release; tod_high = (u32) (get_tod_clock() >> 32); css_generate_pgid(css, tod_high); @@ -931,16 +948,11 @@ static int __init css_bus_init(void) put_device(&css->device); goto out_unregister; } - if (css_chsc_characteristics.secm) { - ret = device_create_file(&css->device, - &dev_attr_cm_enable); - if (ret) - goto out_device; - } ret = device_register(&css->pseudo_subchannel->dev); if (ret) { put_device(&css->pseudo_subchannel->dev); - goto out_file; + device_unregister(&css->device); + goto out_unregister; } } ret = register_reboot_notifier(&css_reboot_notifier); @@ -957,12 +969,6 @@ static int __init css_bus_init(void) isc_register(IO_SCH_ISC); return 0; -out_file: - if (css_chsc_characteristics.secm) - device_remove_file(&channel_subsystems[i]->device, - &dev_attr_cm_enable); -out_device: - device_unregister(&channel_subsystems[i]->device); out_unregister: while (i > 0) { struct channel_subsystem *css; @@ -971,9 +977,6 @@ out_unregister: 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); @@ -993,8 +996,6 @@ static void __init css_bus_cleanup(void) for_each_css(css) { 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); -- cgit v1.2.3-59-g8ed1b From 15a2044d7f3c1ee16de92a45f035f3abbe1bb885 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 25 Oct 2016 14:05:08 +0200 Subject: s390/cio: css initialization cleanup Simplify error handling during css initialization by moving the error handling code to setup_css (which now cleans up after itself). Also remove the odd special cleanup handling of the pseudo_subchannel. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 103 ++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 59bd441b1cd3..8b608e0d2d26 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -714,18 +714,11 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.tod_high = tod_high; } -static void -channel_subsystem_release(struct device *dev) +static void channel_subsystem_release(struct device *dev) { - struct channel_subsystem *css; + struct channel_subsystem *css = to_css(dev); - css = to_css(dev); mutex_destroy(&css->mutex); - if (css->pseudo_subchannel) { - /* Implies that it has been generated but never registered. */ - css_subchannel_release(&css->pseudo_subchannel->dev); - css->pseudo_subchannel = NULL; - } kfree(css); } @@ -790,35 +783,59 @@ static const struct attribute_group *cssdev_attr_groups[] = { static int __init setup_css(int nr) { - u32 tod_high; - int ret; struct channel_subsystem *css; + int ret; - css = channel_subsystems[nr]; - memset(css, 0, sizeof(struct channel_subsystem)); - css->pseudo_subchannel = - kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL); - if (!css->pseudo_subchannel) + css = kzalloc(sizeof(*css), GFP_KERNEL); + if (!css) return -ENOMEM; + + channel_subsystems[nr] = css; + dev_set_name(&css->device, "css%x", nr); + css->device.groups = cssdev_attr_groups; + css->device.release = channel_subsystem_release; + + mutex_init(&css->mutex); + css->valid = 1; + css->cssid = chsc_get_cssid(nr); + css_generate_pgid(css, (u32) (get_tod_clock() >> 32)); + + ret = device_register(&css->device); + if (ret) { + put_device(&css->device); + goto out_err; + } + + css->pseudo_subchannel = kzalloc(sizeof(*css->pseudo_subchannel), + GFP_KERNEL); + if (!css->pseudo_subchannel) { + device_unregister(&css->device); + ret = -ENOMEM; + goto out_err; + } + css->pseudo_subchannel->dev.parent = &css->device; css->pseudo_subchannel->dev.release = css_subchannel_release; - dev_set_name(&css->pseudo_subchannel->dev, "defunct"); mutex_init(&css->pseudo_subchannel->reg_mutex); ret = css_sch_create_locks(css->pseudo_subchannel); if (ret) { kfree(css->pseudo_subchannel); - return ret; + device_unregister(&css->device); + goto out_err; } - mutex_init(&css->mutex); - css->valid = 1; - css->cssid = chsc_get_cssid(nr); - dev_set_name(&css->device, "css%x", nr); - css->device.groups = cssdev_attr_groups; - css->device.release = channel_subsystem_release; - tod_high = (u32) (get_tod_clock() >> 32); - css_generate_pgid(css, tod_high); - return 0; + dev_set_name(&css->pseudo_subchannel->dev, "defunct"); + ret = device_register(&css->pseudo_subchannel->dev); + if (ret) { + put_device(&css->pseudo_subchannel->dev); + device_unregister(&css->device); + goto out_err; + } + + return ret; +out_err: + channel_subsystems[nr] = NULL; + return ret; } static int css_reboot_event(struct notifier_block *this, @@ -930,30 +947,9 @@ static int __init css_bus_init(void) /* Setup css structure. */ for (i = 0; i <= MAX_CSS_IDX; i++) { - struct channel_subsystem *css; - - css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); - if (!css) { - ret = -ENOMEM; - goto out_unregister; - } - channel_subsystems[i] = css; ret = setup_css(i); - if (ret) { - kfree(channel_subsystems[i]); + if (ret) goto out_unregister; - } - ret = device_register(&css->device); - if (ret) { - put_device(&css->device); - goto out_unregister; - } - ret = device_register(&css->pseudo_subchannel->dev); - if (ret) { - put_device(&css->pseudo_subchannel->dev); - device_unregister(&css->device); - goto out_unregister; - } } ret = register_reboot_notifier(&css_reboot_notifier); if (ret) @@ -970,13 +966,9 @@ static int __init css_bus_init(void) return 0; out_unregister: - while (i > 0) { - struct channel_subsystem *css; - - i--; - css = channel_subsystems[i]; + while (i-- > 0) { + struct channel_subsystem *css = channel_subsystems[i]; device_unregister(&css->pseudo_subchannel->dev); - css->pseudo_subchannel = NULL; device_unregister(&css->device); } bus_unregister(&css_bus_type); @@ -995,7 +987,6 @@ static void __init css_bus_cleanup(void) for_each_css(css) { device_unregister(&css->pseudo_subchannel->dev); - css->pseudo_subchannel = NULL; device_unregister(&css->device); } bus_unregister(&css_bus_type); -- cgit v1.2.3-59-g8ed1b From 64dfdd4b539f0d2e552e8b83aab119c8eafbbc83 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 11 Oct 2016 18:21:36 +0200 Subject: s390/cio: export real cssid Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 8b608e0d2d26..8faffed61092 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -722,6 +722,18 @@ static void channel_subsystem_release(struct device *dev) kfree(css); } +static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a, + char *buf) +{ + struct channel_subsystem *css = to_css(dev); + + if (css->cssid < 0) + return -EINVAL; + + return sprintf(buf, "%x\n", css->cssid); +} +static DEVICE_ATTR_RO(real_cssid); + static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a, char *buf) { @@ -766,6 +778,15 @@ static umode_t cm_enable_mode(struct kobject *kobj, struct attribute *attr, return css_chsc_characteristics.secm ? attr->mode : 0; } +static struct attribute *cssdev_attrs[] = { + &dev_attr_real_cssid.attr, + NULL, +}; + +static struct attribute_group cssdev_attr_group = { + .attrs = cssdev_attrs, +}; + static struct attribute *cssdev_cm_attrs[] = { &dev_attr_cm_enable.attr, NULL, @@ -777,6 +798,7 @@ static struct attribute_group cssdev_cm_attr_group = { }; static const struct attribute_group *cssdev_attr_groups[] = { + &cssdev_attr_group, &cssdev_cm_attr_group, NULL, }; -- cgit v1.2.3-59-g8ed1b From 00851e6925a827362e3b84ead0c0cf3e86a31aec Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 8 Nov 2016 17:50:40 +0100 Subject: s390/cio: remove unused struct member Remove an unused member of struct channel subsystem. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 1 - drivers/s390/cio/css.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 8faffed61092..e2aa944eb566 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -818,7 +818,6 @@ static int __init setup_css(int nr) css->device.release = channel_subsystem_release; mutex_init(&css->mutex); - css->valid = 1; css->cssid = chsc_get_cssid(nr); css_generate_pgid(css, (u32) (get_tod_clock() >> 32)); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 3056f96f9d82..c9f3fb39ebeb 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -114,7 +114,6 @@ void css_update_ssd_info(struct subchannel *sch); struct channel_subsystem { int cssid; - int valid; struct channel_path *chps[__MAX_CHPID + 1]; struct device device; struct pgid global_pgid; -- cgit v1.2.3-59-g8ed1b From dd695546603e8f984137d4dc806dd12e19b6bc27 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Dec 2016 15:18:23 +0100 Subject: s390/zcore: remove unneeded linux/miscdevice.h include drivers/s390/char/zcore.c does not contain any miscdevice so the inclusion of linux/miscdevice.h is uncessary. Signed-off-by: Corentin Labbe Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/zcore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index d3b51edb056e..863211a0b312 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -15,7 +15,6 @@ #include #include -#include #include #include -- cgit v1.2.3-59-g8ed1b From 90b3baa232ea6938ab707e3db2e90609494e6c54 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 20 Dec 2016 16:08:05 +0100 Subject: s390: proper type casts for csum_partial invocations Keep sparse and other static code checkers from emitting warnings like: arch/s390/kernel/ipl.c:1549:14: warning: incorrect type in assignment (different base types) arch/s390/kernel/ipl.c:1549:14: expected unsigned int [unsigned] csum arch/s390/kernel/ipl.c:1549:14: got restricted __wsum All usages in s390 code are ok. Therefore add proper casts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ipl.c | 3 ++- arch/s390/kernel/os_info.c | 6 +++--- drivers/s390/char/zcore.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index ff3364a067ff..2c6ddced5394 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -1546,7 +1546,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger) unsigned long ipib = (unsigned long) reipl_block_actual; unsigned int csum; - csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); + csum = (__force unsigned int) + csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); mem_assign_absolute(S390_lowcore.ipib, ipib); mem_assign_absolute(S390_lowcore.ipib_checksum, csum); dump_run(trigger); diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c index 87f05e475ae8..753ba63182b9 100644 --- a/arch/s390/kernel/os_info.c +++ b/arch/s390/kernel/os_info.c @@ -26,7 +26,7 @@ static struct os_info os_info __page_aligned_data; u32 os_info_csum(struct os_info *os_info) { int size = sizeof(*os_info) - offsetof(struct os_info, version_major); - return csum_partial(&os_info->version_major, size, 0); + return (__force u32)csum_partial(&os_info->version_major, size, 0); } /* @@ -46,7 +46,7 @@ void os_info_entry_add(int nr, void *ptr, u64 size) { os_info.entry[nr].addr = (u64)(unsigned long)ptr; os_info.entry[nr].size = size; - os_info.entry[nr].csum = csum_partial(ptr, size, 0); + os_info.entry[nr].csum = (__force u32)csum_partial(ptr, size, 0); os_info.csum = os_info_csum(&os_info); } @@ -93,7 +93,7 @@ static void os_info_old_alloc(int nr, int align) msg = "copy failed"; goto fail_free; } - csum = csum_partial(buf_align, size, 0); + csum = (__force u32)csum_partial(buf_align, size, 0); if (csum != os_info_old->entry[nr].csum) { msg = "checksum failed"; goto fail_free; diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 863211a0b312..aaed778f67c4 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -272,7 +272,7 @@ static int __init zcore_reipl_init(void) rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); else rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); - if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) != + if (rc || (__force u32)csum_partial(ipl_block, ipl_block->hdr.len, 0) != ipib_info.checksum) { TRACE("Checksum does not match\n"); free_page((unsigned long) ipl_block); -- cgit v1.2.3-59-g8ed1b From 5064cd35062be01cba4b3fa895bdbeb8a9759213 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Sat, 17 Dec 2016 15:35:39 +0100 Subject: s390/pci: use proper endianness annotations Add proper annotation to the bar definition and use casts within the bus accessors. Also change the sequence in the accessors to do the shifts in the native byte order. No functional change. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/pci_clp.h | 2 +- arch/s390/pci/pci.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index d6f1b1d94352..938b8cc19fc6 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -85,7 +85,7 @@ struct clp_rsp_query_pci { u32 fid; /* pci function id */ u8 bar_size[PCI_BAR_COUNT]; u16 pchid; - u32 bar[PCI_BAR_COUNT]; + __le32 bar[PCI_BAR_COUNT]; u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ u32 : 16; u8 fmb_len; diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 38e17d4d9884..4c0fa9b3b2a0 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -224,8 +224,8 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) rc = zpci_load(&data, req, offset); if (!rc) { - data = data << ((8 - len) * 8); - data = le64_to_cpu(data); + data = le64_to_cpu((__force __le64) data); + data >>= (8 - len) * 8; *val = (u32) data; } else *val = 0xffffffff; @@ -238,8 +238,8 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len) u64 data = val; int rc; - data = cpu_to_le64(data); - data = data >> ((8 - len) * 8); + data <<= (8 - len) * 8; + data = (__force u64) cpu_to_le64(data); rc = zpci_store(data, req, offset); return rc; } -- cgit v1.2.3-59-g8ed1b From 7be5e359a7eaea6ebe761044f6994163f0dd8585 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 27 Dec 2016 14:47:42 +0100 Subject: s390/setup: call memblock_reserve only for size > 0 reserve_initrd currently calls memblock_reserve even if the to be reserved size is zero. Even though the memblock core code can handle this correctly, it still yields confusing debug messages if memblock debugging is enabled. Therefore make sure to not call memblock_reserve with a size of zero. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 865a48871ca4..1a3388c32a83 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -636,6 +636,8 @@ static void __init reserve_crashkernel(void) static void __init reserve_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD + if (!INITRD_START || !INITRD_SIZE) + return; initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; memblock_reserve(INITRD_START, INITRD_SIZE); -- cgit v1.2.3-59-g8ed1b From a2ce2a956814b52c062d17422ebbf87ce4f0158d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 27 Dec 2016 15:14:26 +0100 Subject: s390/mem_detect: add debugging output The s390 specific memory detection code does not call memblock_add, which would generate debug output if memblock=debug is specified on the kernel command line. Instead it directly calls memblock_add_range, which doesn't generate any debug output. To have a chance to debug early memblock related bugs add an s390 specific memblock_dbg call and a (missing) memblock_dump_all call. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/mem_detect.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c index d612cc3eec6a..0389d8d24358 100644 --- a/arch/s390/mm/mem_detect.c +++ b/arch/s390/mm/mem_detect.c @@ -19,6 +19,8 @@ static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size) { + memblock_dbg("memblock_physmem_add: [%#016llx-%#016llx]\n", + start, start + size - 1); memblock_add_range(&memblock.memory, start, size, 0, 0); memblock_add_range(&memblock.physmem, start, size, 0, 0); } @@ -55,4 +57,5 @@ void __init detect_memory_memblock(void) memblock_set_bottom_up(false); if (!max_physmem_end) max_physmem_end = memblock_end_of_DRAM(); + memblock_dump_all(); } -- cgit v1.2.3-59-g8ed1b From 00de54c803d5526a791112e653614656365c5578 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 27 Dec 2016 15:36:34 +0100 Subject: s390/mem_detect: fix memory type of first block Fix a long-standing but currently irrelevant bug: the memory detection code performs a tprot instruction on address zero to figure out if the first memory chunk is readable or writable. Due to low address protection the result is "read-only". If the memory detection code would actually care, it would have to ignore the first memory increment, but it adds the memory increment to writable memory anyway. If memblock debugging is enabled this leads to an extra rather surprising call which registers memory. To avoid this get rid of the first misleading tprot call and simply assume that the first memory increment is writable. Otherwise we wouldn't have reached the memory detection code anyway. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/mem_detect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c index 0389d8d24358..185e70d3e153 100644 --- a/arch/s390/mm/mem_detect.c +++ b/arch/s390/mm/mem_detect.c @@ -41,7 +41,8 @@ void __init detect_memory_memblock(void) memblock_set_bottom_up(true); do { size = 0; - type = tprot(addr); + /* assume lowcore is writable */ + type = addr ? tprot(addr) : CHUNK_READ_WRITE; do { size += rzm; if (max_physmem_end && addr + size >= max_physmem_end) -- cgit v1.2.3-59-g8ed1b From 496e59cc48e8bb4e612ecde507d8249abdc9e6e5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 2 Jan 2017 08:15:07 +0100 Subject: s390/topology: reduce number of printks Merge the seven printks within topology_init_early to a single one. With an early boot console this avoids printing six lines each containing only a single character. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/topology.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 93dcbae1e98d..4d16495b4f01 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -461,7 +461,6 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info, void __init topology_init_early(void) { struct sysinfo_15_1_x *info; - int i; set_sched_topology(s390_topology); if (!MACHINE_HAS_TOPOLOGY) @@ -469,10 +468,9 @@ void __init topology_init_early(void) tl_info = memblock_virt_alloc(sizeof(*tl_info), PAGE_SIZE); info = tl_info; store_topology(info); - pr_info("The CPU configuration topology of the machine is:"); - for (i = 0; i < TOPOLOGY_NR_MAG; i++) - printk(KERN_CONT " %d", info->mag[i]); - printk(KERN_CONT " / %d\n", info->mnest); + pr_info("The CPU configuration topology of the machine is: %d %d %d %d %d %d / %d\n", + info->mag[0], info->mag[1], info->mag[2], info->mag[3], + info->mag[4], info->mag[5], info->mnest); alloc_masks(info, &socket_info, 1); alloc_masks(info, &book_info, 2); alloc_masks(info, &drawer_info, 3); -- cgit v1.2.3-59-g8ed1b From 0b92515916799ca2711c7c46abccb96c275cc88a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 2 Jan 2017 08:51:02 +0100 Subject: s390: remove couple of unneeded semicolons Remove a couple of unneeded semicolons. This is just to reduce the noise that the coccinelle static code checker generates. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/uaccess.h | 4 ++-- arch/s390/kernel/perf_cpum_cf_events.c | 2 +- arch/s390/kvm/priv.c | 2 +- arch/s390/kvm/vsie.c | 2 +- arch/s390/mm/extmem.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index f82b04e85a21..3d1d0f7b7d28 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -177,7 +177,7 @@ static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) (unsigned long *)x, size, spec); break; - }; + } return rc; } @@ -207,7 +207,7 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s (unsigned long __user *)ptr, size, spec); break; - }; + } return rc; } diff --git a/arch/s390/kernel/perf_cpum_cf_events.c b/arch/s390/kernel/perf_cpum_cf_events.c index 4554a4bae39e..c343ac2cf6c5 100644 --- a/arch/s390/kernel/perf_cpum_cf_events.c +++ b/arch/s390/kernel/perf_cpum_cf_events.c @@ -309,7 +309,7 @@ __init const struct attribute_group **cpumf_cf_event_group(void) default: model = NULL; break; - }; + } if (!model) goto out; diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index e18435355c16..794503516bd4 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -311,7 +311,7 @@ static int handle_sske(struct kvm_vcpu *vcpu) if (rc < 0) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); start += PAGE_SIZE; - }; + } if (m3 & (SSKE_MC | SSKE_MR)) { if (m3 & SSKE_MB) { diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index d8673e243f13..a9a9d974d9a4 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -899,7 +899,7 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (rc || scb_s->icptcode || signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0)) break; - }; + } if (rc == -EFAULT) { /* diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 362237203144..91af69f1dce5 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -154,7 +154,7 @@ dcss_mkname(char *name, char *dcss_name) if (name[i] == '\0') break; dcss_name[i] = toupper(name[i]); - }; + } for (; i < 8; i++) dcss_name[i] = ' '; ASCEBC(dcss_name, 8); -- cgit v1.2.3-59-g8ed1b From 970ba6ac6a59ff1f1579e472a97765adc50186f9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 2 Jan 2017 09:59:40 +0100 Subject: s390: use false/true when using bool Yet another trivial patch to reduce the noise that coccinelle generates. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/processor.c | 2 +- arch/s390/kernel/time.c | 2 +- drivers/s390/char/con3270.c | 2 +- drivers/s390/char/raw3270.c | 2 +- drivers/s390/crypto/zcrypt_api.c | 4 ++-- drivers/s390/virtio/virtio_ccw.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 9e60ef144d03..8733b07b5691 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -32,7 +32,7 @@ static bool machine_has_cpu_mhz; void __init cpu_detect_mhz_feature(void) { if (test_facility(34) && __ecag(ECAG_CPU_ATTRIBUTE, 0) != -1UL) - machine_has_cpu_mhz = 1; + machine_has_cpu_mhz = true; } static void update_cpu_mhz(void *arg) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 52949df88529..eebbd6adc6c5 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -492,7 +492,7 @@ static void __init stp_reset(void) pr_warn("The real or virtual hardware system does not provide an STP interface\n"); free_page((unsigned long) stp_page); stp_page = NULL; - stp_online = 0; + stp_online = false; } } diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 285b4006f44b..8522cfce5b4e 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -31,7 +31,7 @@ static struct raw3270_fn con3270_fn; -static bool auto_update = 1; +static bool auto_update = true; module_param(auto_update, bool, 0); /* diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index a2da898ce90f..710f2292911d 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -82,7 +82,7 @@ static LIST_HEAD(raw3270_devices); static int raw3270_registered; /* Module parameters */ -static bool tubxcorrect = 0; +static bool tubxcorrect; module_param(tubxcorrect, bool, 0); /* diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 51eece9af577..919f7aa5a09a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -201,7 +201,7 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc, unsigned weight, unsigned pref_weight) { if (!pref_zc) - return 0; + return false; weight += atomic_read(&zc->load); pref_weight += atomic_read(&pref_zc->load); if (weight == pref_weight) @@ -215,7 +215,7 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, unsigned weight, unsigned pref_weight) { if (!pref_zq) - return 0; + return false; weight += atomic_read(&zq->load); pref_weight += atomic_read(&pref_zq->load); if (weight == pref_weight) diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 639ed4e6afd1..879a5f63e7d4 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -659,7 +659,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw); if (ret) /* no error, just fall back to legacy interrupts */ - vcdev->is_thinint = 0; + vcdev->is_thinint = false; } if (!vcdev->is_thinint) { /* Register queue indicators with host. */ -- cgit v1.2.3-59-g8ed1b From 68cc795d1933285705ced6d841ef66c00ce98cbe Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 29 Dec 2016 13:52:52 +0100 Subject: s390/topology: make "topology=off" parameter work The "topology=off" kernel parameter is supposed to prevent the kernel to use hardware topology information to generate scheduling domains etc. For an unknown reason I implemented this in a very odd way back then: instead of simply clearing the MACHINE_HAS_TOPOLOGY flag within the lowcore I added a second variable which indicated that topology information should not be used. This is more than suboptimal since it partially doesn't work. For the fake NUMA case topology information is still considered and scheduling domains will be created based on this. To fix this and to simplify the code get rid of the extra variable and implement the "topology=off" case like it is done for other features. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/early.c | 12 ++++++++++++ arch/s390/kernel/topology.c | 11 ++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 324f1c147a41..d756315b7985 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -364,6 +364,18 @@ static inline void save_vector_registers(void) #endif } +static int __init topology_setup(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (!rc && !enabled) + S390_lowcore.machine_flags &= ~MACHINE_HAS_TOPOLOGY; + return rc; +} +early_param("topology", topology_setup); + static int __init disable_vector_extension(char *str) { S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 4d16495b4f01..7b2b19b0b294 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -38,7 +38,6 @@ static void set_topology_timer(void); static void topology_work_fn(struct work_struct *work); static struct sysinfo_15_1_x *tl_info; -static bool topology_enabled = true; static DECLARE_WORK(topology_work, topology_work_fn); /* @@ -59,7 +58,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_t mask; cpumask_copy(&mask, cpumask_of(cpu)); - if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) + if (!MACHINE_HAS_TOPOLOGY) return mask; for (; info; info = info->next) { if (cpumask_test_cpu(cpu, &info->mask)) @@ -74,7 +73,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) int i; cpumask_copy(&mask, cpumask_of(cpu)); - if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) + if (!MACHINE_HAS_TOPOLOGY) return mask; cpu -= cpu % (smp_cpu_mtid + 1); for (i = 0; i <= smp_cpu_mtid; i++) @@ -428,12 +427,6 @@ static const struct cpumask *cpu_drawer_mask(int cpu) return &cpu_topology[cpu].drawer_mask; } -static int __init early_parse_topology(char *p) -{ - return kstrtobool(p, &topology_enabled); -} -early_param("topology", early_parse_topology); - static struct sched_domain_topology_level s390_topology[] = { { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, -- cgit v1.2.3-59-g8ed1b From 742dc5773cf5bbb355e4b4dd61310d5f51556477 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 11 Jan 2017 09:14:45 +0100 Subject: s390/sclp: make early sclp irq handler more robust Make the early sclp interrupt handler more robust: - disable all interrupt sub classes except for the service signal subclass - extend ctlreg0 union so it is easily possible to set the service signal subclass mask bit without using a magic number - disable lowcore protection before writing to it - make sure that all write accesses are done before the original content of control register 0 is restored, which could enable lowcore protection Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ctl_reg.h | 4 +++- arch/s390/kernel/sclp.c | 15 ++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index 8e136b88cdf4..cf4c9a106049 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -62,7 +62,9 @@ union ctlreg0 { unsigned long : 4; unsigned long afp : 1; /* AFP-register control */ unsigned long vx : 1; /* Vector enablement control */ - unsigned long : 17; + unsigned long : 7; + unsigned long sssm : 1; /* Service signal subclass mask */ + unsigned long : 9; }; }; diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c index f08af675f36f..745324349a7b 100644 --- a/arch/s390/kernel/sclp.c +++ b/arch/s390/kernel/sclp.c @@ -18,12 +18,16 @@ static bool have_linemode __section(data); static void _sclp_wait_int(void) { - unsigned long cr0, cr0_new, psw_mask, addr; + unsigned long psw_mask, addr, flags; psw_t psw_ext_save, psw_wait; + union ctlreg0 cr0, cr0_new; - __ctl_store(cr0, 0, 0); - cr0_new = cr0 | 0x200; - __ctl_load(cr0_new, 0, 0); + raw_local_irq_save(flags); + __ctl_store(cr0.val, 0, 0); + cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; + cr0_new.lap = 0; + cr0_new.sssm = 1; + __ctl_load(cr0_new.val, 0, 0); psw_ext_save = S390_lowcore.external_new_psw; psw_mask = __extract_psw(); @@ -45,8 +49,9 @@ static void _sclp_wait_int(void) : "cc", "memory"); } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG); - __ctl_load(cr0, 0, 0); S390_lowcore.external_new_psw = psw_ext_save; + __ctl_load(cr0.val, 0, 0); + raw_local_irq_restore(flags); } static int _sclp_servc(unsigned int cmd, char *sccb) -- cgit v1.2.3-59-g8ed1b From f0319748599183fa71a1e8792317385313ed946b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 11 Jan 2017 11:07:39 +0100 Subject: s390/sclp: always stay within bounds of the early sccb Make sure the _sclp_print_lm function stays within bounds of the early sccb, even if the passed string is very long. If the string is too long, the remaining characters will be dropped. Suggested-by: Peter Oberparleiter Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/sclp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c index 745324349a7b..53e391fe8577 100644 --- a/arch/s390/kernel/sclp.c +++ b/arch/s390/kernel/sclp.c @@ -132,16 +132,21 @@ static void _sclp_print_lm(const char *str) 0x10, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00 /* 6 */ }; - unsigned char *ptr, ch; + unsigned char *ptr, *end_ptr, ch; unsigned int count; memcpy(_sclp_work_area, write_head, sizeof(write_head)); ptr = _sclp_work_area + sizeof(write_head); + end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; do { + if (ptr + sizeof(write_mto) > end_ptr) + break; memcpy(ptr, write_mto, sizeof(write_mto)); for (count = sizeof(write_mto); (ch = *str++) != 0; count++) { if (ch == 0x0a) break; + if (ptr > end_ptr) + break; ptr[count] = _ascebc[ch]; } /* Update length fields in mto, mdb, evbuf and sccb */ -- cgit v1.2.3-59-g8ed1b From 89175cf766869307c4f57a7a5f63d2819e76c41b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 11 Jan 2017 09:14:52 +0100 Subject: s390: provide sclp based boot console Use the early sclp code to provide a boot console. This boot console is available if the kernel parameter "earlyprintk" has been specified, just like it works for other architectures that also provide an early boot console. This makes debugging of early problems much easier, since now we finally have working console output even before memory detection is running. The boot console will be automatically disabled as soon as another console will be registered. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- Documentation/admin-guide/kernel-parameters.txt | 5 +++- arch/s390/Kconfig.debug | 4 +++ arch/s390/include/asm/sclp.h | 1 + arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/early_printk.c | 35 +++++++++++++++++++++++++ arch/s390/kernel/sclp.c | 25 +++++++++++------- 6 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 arch/s390/kernel/early_printk.c diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index be7c0d9506b1..ef77c55e87e2 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -979,9 +979,10 @@ address. The serial port must already be setup and configured. Options are not yet supported. - earlyprintk= [X86,SH,BLACKFIN,ARM,M68k] + earlyprintk= [X86,SH,BLACKFIN,ARM,M68k,S390] earlyprintk=vga earlyprintk=efi + earlyprintk=sclp earlyprintk=xen earlyprintk=serial[,ttySn[,baudrate]] earlyprintk=serial[,0x...[,baudrate]] @@ -1016,6 +1017,8 @@ The xen output can only be used by Xen PV guests. + The sclp output can only be used on s390. + edac_report= [HW,EDAC] Control how to report EDAC event Format: {"on" | "off" | "force"} on: enable EDAC to report H/W event. May be overridden diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 26c5d5beb4be..32b3e3bfd022 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -20,4 +20,8 @@ config S390_PTDUMP config DEBUG_SET_MODULE_RONX def_bool y depends on MODULES + +config EARLY_PRINTK + def_bool y + endmenu diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 8db92a5b3bf1..415eaace3f1b 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -118,6 +118,7 @@ int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); void sclp_early_detect(void); void _sclp_print_early(const char *); +void __sclp_print_early(const char *s, unsigned int len); void sclp_ocf_cpc_name_copy(char *dst); static inline int sclp_get_core_info(struct sclp_core_info *info, int early) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 36b5101c8606..edbc62e04027 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -76,7 +76,7 @@ obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y) - +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c new file mode 100644 index 000000000000..54a4dc582b81 --- /dev/null +++ b/arch/s390/kernel/early_printk.c @@ -0,0 +1,35 @@ +/* + * Copyright IBM Corp. 2017 + */ + +#include +#include +#include +#include + +static void sclp_early_write(struct console *con, const char *s, unsigned int len) +{ + __sclp_print_early(s, len); +} + +static struct console sclp_early_console = { + .name = "earlysclp", + .write = sclp_early_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +static int __init setup_early_printk(char *buf) +{ + if (early_console) + return 0; + /* Accept only "earlyprintk" and "earlyprintk=sclp" */ + if (buf && strncmp(buf, "sclp", 4)) + return 0; + if (!sclp.has_linemode && !sclp.has_vt220) + return 0; + early_console = &sclp_early_console; + register_console(early_console); + return 0; +} +early_param("earlyprintk", setup_early_printk); diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c index 53e391fe8577..f9c5b02d2685 100644 --- a/arch/s390/kernel/sclp.c +++ b/arch/s390/kernel/sclp.c @@ -98,7 +98,7 @@ static int _sclp_setup(int disable) } /* Output multi-line text using SCLP Message interface. */ -static void _sclp_print_lm(const char *str) +static void _sclp_print_lm(const char *str, unsigned int len) { static unsigned char write_head[] = { /* sccb header */ @@ -133,8 +133,9 @@ static void _sclp_print_lm(const char *str) 0x00, 0x00, 0x00, 0x00 /* 6 */ }; unsigned char *ptr, *end_ptr, ch; - unsigned int count; + unsigned int count, num; + num = 0; memcpy(_sclp_work_area, write_head, sizeof(write_head)); ptr = _sclp_work_area + sizeof(write_head); end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; @@ -142,7 +143,9 @@ static void _sclp_print_lm(const char *str) if (ptr + sizeof(write_mto) > end_ptr) break; memcpy(ptr, write_mto, sizeof(write_mto)); - for (count = sizeof(write_mto); (ch = *str++) != 0; count++) { + for (count = sizeof(write_mto); num < len; count++) { + num++; + ch = *str++; if (ch == 0x0a) break; if (ptr > end_ptr) @@ -155,7 +158,7 @@ static void _sclp_print_lm(const char *str) *(unsigned short *)(_sclp_work_area + 8) += count; *(unsigned short *)(_sclp_work_area + 0) += count; ptr += count; - } while (ch != 0); + } while (num < len); /* SCLP write data */ _sclp_servc(0x00760005, _sclp_work_area); @@ -164,7 +167,7 @@ static void _sclp_print_lm(const char *str) /* Output multi-line text (plus a newline) using SCLP VT220 * interface. */ -static void _sclp_print_vt220(const char *str) +static void _sclp_print_vt220(const char *str, unsigned int len) { static unsigned char const write_head[] = { /* sccb header */ @@ -174,7 +177,6 @@ static void _sclp_print_vt220(const char *str) 0x00, 0x06, 0x1a, 0x00, 0x00, 0x00, }; - size_t len = strlen(str); if (sizeof(write_head) + len >= sizeof(_sclp_work_area)) len = sizeof(_sclp_work_area) - sizeof(write_head) - 1; @@ -194,13 +196,18 @@ static void _sclp_print_vt220(const char *str) /* Output one or more lines of text on the SCLP console (VT220 and / * or line-mode). All lines get terminated; no need for a trailing LF. */ -void _sclp_print_early(const char *str) +void __sclp_print_early(const char *str, unsigned int len) { if (_sclp_setup(0) != 0) return; if (have_linemode) - _sclp_print_lm(str); + _sclp_print_lm(str, len); if (have_vt220) - _sclp_print_vt220(str); + _sclp_print_vt220(str, len); _sclp_setup(1); } + +void _sclp_print_early(const char *str) +{ + __sclp_print_early(str, strlen(str)); +} -- cgit v1.2.3-59-g8ed1b From 21665912dd722656dfc4481f82c73397c8f2d07f Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 12 Jan 2017 18:53:56 +0100 Subject: s390/cio: remove cmf related code relevant for 31 bit only This is a leftover from the 31 bit era to avoid 64 bit divisions. Get rid of it. Reported-by: Heiko Carstens Signed-off-by: Sebastian Ott Acked-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cmf.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 6b6386e9a500..220491d27ef4 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1085,15 +1085,9 @@ static ssize_t cmb_show_avg_utilization(struct device *dev, data.function_pending_time + data.device_disconnect_time; - /* shift to avoid long long division */ - while (-1ul < (data.elapsed_time | utilization)) { - utilization >>= 8; - data.elapsed_time >>= 8; - } - /* calculate value in 0.1 percent units */ - t = (unsigned long) data.elapsed_time / 1000; - u = (unsigned long) utilization / t; + t = data.elapsed_time / 1000; + u = utilization / t; return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10); } -- cgit v1.2.3-59-g8ed1b From 9437964885f84cd0c584e2d30ffbf7a5a84b77e4 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 14 Jan 2017 01:48:24 +0100 Subject: s390/bpf: remove redundant check for non-null image After we already allocated the jit.prg_buf image via bpf_jit_binary_alloc() and filled it out with instructions, jit.prg_buf cannot be NULL anymore. Thus, remove the unnecessary check. Tested on s390x with test_bpf module. Signed-off-by: Daniel Borkmann Cc: Michael Holzheu Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/net/bpf_jit_comp.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 167b31b186c1..b3b0af86b84e 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1331,14 +1331,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) } if (bpf_jit_enable > 1) { bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf); - if (jit.prg_buf) - print_fn_code(jit.prg_buf, jit.size_prg); - } - if (jit.prg_buf) { - set_memory_ro((unsigned long)header, header->pages); - fp->bpf_func = (void *) jit.prg_buf; - fp->jited = 1; + print_fn_code(jit.prg_buf, jit.size_prg); } + set_memory_ro((unsigned long)header, header->pages); + fp->bpf_func = (void *) jit.prg_buf; + fp->jited = 1; free_addrs: kfree(jit.addrs); out: -- cgit v1.2.3-59-g8ed1b From f3d3584faf29e8901e00794f4e5f770b9f1eb7a6 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Thu, 15 Dec 2016 14:54:30 +0100 Subject: s390/crypto: Check des3_ede keys for uniqueness in fips mode Triple-DES implementations will soon be required to check for uniqueness of keys with fips mode enabled. Add checks to ensure none of the 3 keys match. Signed-off-by: Matthew Rosato Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/crypto/des_s390.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 8b83144206eb..0d296662bbf0 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -221,6 +222,8 @@ static struct crypto_alg cbc_des_alg = { * same as DES. Implementers MUST reject keys that exhibit this * property. * + * In fips mode additinally check for all 3 keys are unique. + * */ static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) @@ -234,6 +237,17 @@ static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } + + /* in fips mode, ensure k1 != k2 and k2 != k3 and k1 != k3 */ + if (fips_enabled && + !(crypto_memneq(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && + crypto_memneq(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], + DES_KEY_SIZE) && + crypto_memneq(key, &key[DES_KEY_SIZE * 2], DES_KEY_SIZE))) { + tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; + } + memcpy(ctx->key, key, key_len); return 0; } -- cgit v1.2.3-59-g8ed1b From a4f2779ecf2f42b0997fedef6fd20a931c40a3e3 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 15 Dec 2016 14:58:08 +0100 Subject: s390/crypto: Extend key length check for AES-XTS in fips mode. In fips mode only xts keys with 128 bit or 125 bit are allowed. This fix extends the xts_aes_set_key function to check for these valid key lengths in fips mode. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/crypto/aes_s390.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 303d28eb03a2..591cbdf615af 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -501,6 +502,12 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, if (err) return err; + /* In fips mode only 128 bit or 256 bit keys are valid */ + if (fips_enabled && key_len != 32 && key_len != 64) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + /* Pick the correct function code based on the key length */ fc = (key_len == 32) ? CPACF_KM_XTS_128 : (key_len == 64) ? CPACF_KM_XTS_256 : 0; -- cgit v1.2.3-59-g8ed1b From d34b1acb78af41b8b8d5c60972b6555ea19f7564 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 20 Dec 2016 11:32:47 +0100 Subject: s390/prng: Adjust generation of entropy to produce real 256 bits. The generate_entropy function used a sha256 for compacting together 256 bits of entropy into 32 bytes hash. However, it is questionable if a sha256 can really be used here, as potential collisions may reduce the max entropy fitting into a 32 byte hash value. So this batch introduces the use of sha512 instead and the required buffer adjustments for the calling functions. Further more the working buffer for the generate_entropy function has been widened from one page to two pages. So now 1024 stckf invocations are used to gather 256 bits of entropy. This has been done to be on the save side if the jitters of stckf values isn't as good as supposed. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/crypto/prng.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index daf9bb063aaa..85b7f5efe06a 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = { /*** helper functions ***/ +/* + * generate_entropy: + * This algorithm produces 64 bytes of entropy data based on 1024 + * individual stckf() invocations assuming that each stckf() value + * contributes 0.25 bits of entropy. So the caller gets 256 bit + * entropy per 64 byte or 4 bits entropy per byte. + */ static int generate_entropy(u8 *ebuf, size_t nbytes) { int n, ret = 0; - u8 *pg, *h, hash[32]; + u8 *pg, *h, hash[64]; - pg = (u8 *) __get_free_page(GFP_KERNEL); + /* allocate 2 pages */ + pg = (u8 *) __get_free_pages(GFP_KERNEL, 1); if (!pg) { prng_errorflag = PRNG_GEN_ENTROPY_FAILED; return -ENOMEM; } while (nbytes) { - /* fill page with urandom bytes */ - get_random_bytes(pg, PAGE_SIZE); - /* exor page with stckf values */ - for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) { + /* fill pages with urandom bytes */ + get_random_bytes(pg, 2*PAGE_SIZE); + /* exor pages with 1024 stckf values */ + for (n = 0; n < 2 * PAGE_SIZE / sizeof(u64); n++) { u64 *p = ((u64 *)pg) + n; *p ^= get_tod_clock_fast(); } @@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) h = hash; else h = ebuf; - /* generate sha256 from this page */ - cpacf_kimd(CPACF_KIMD_SHA_256, h, pg, PAGE_SIZE); + /* hash over the filled pages */ + cpacf_kimd(CPACF_KIMD_SHA_512, h, pg, 2*PAGE_SIZE); if (n < sizeof(hash)) memcpy(ebuf, hash, n); ret += n; @@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) nbytes -= n; } - free_page((unsigned long)pg); + free_pages((unsigned long)pg, 1); return ret; } @@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void) static int __init prng_sha512_instantiate(void) { int ret, datalen; - u8 seed[64]; + u8 seed[64 + 32 + 16]; pr_debug("prng runs in SHA-512 mode " "with chunksize=%d and reseed_limit=%u\n", @@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void) if (ret) goto outfree; - /* generate initial seed bytestring, first 48 bytes of entropy */ - ret = generate_entropy(seed, 48); - if (ret != 48) + /* generate initial seed bytestring, with 256 + 128 bits entropy */ + ret = generate_entropy(seed, 64 + 32); + if (ret != 64 + 32) goto outfree; /* followed by 16 bytes of unique nonce */ - get_tod_clock_ext(seed + 48); + get_tod_clock_ext(seed + 64 + 32); /* initial seed of the ppno drng */ cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED, @@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void) static int prng_sha512_reseed(void) { int ret; - u8 seed[32]; + u8 seed[64]; - /* generate 32 bytes of fresh entropy */ + /* fetch 256 bits of fresh entropy */ ret = generate_entropy(seed, sizeof(seed)); if (ret != sizeof(seed)) return ret; -- cgit v1.2.3-59-g8ed1b From 7fbe5c0f2af3ab82fe6880af557e98a10d711370 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Mon, 16 Jan 2017 09:43:29 +0100 Subject: s390/zcrypt: use spin_lock_bh for all queue locks and unlocks. During tests the Kernel complained about inconsistend lock state: inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. Now all the queue locks use spin_lock_bh/spin_unlock_bh. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 919f7aa5a09a..926169c3d9b9 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -668,6 +668,7 @@ static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) memset(qdepth, 0, sizeof(char) * AP_DEVICES); spin_lock(&zcrypt_list_lock); + local_bh_disable(); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) @@ -679,6 +680,7 @@ static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) spin_unlock(&zq->queue->lock); } } + local_bh_enable(); spin_unlock(&zcrypt_list_lock); } @@ -689,6 +691,7 @@ static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) memset(reqcnt, 0, sizeof(int) * AP_DEVICES); spin_lock(&zcrypt_list_lock); + local_bh_disable(); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) @@ -699,6 +702,7 @@ static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) spin_unlock(&zq->queue->lock); } } + local_bh_enable(); spin_unlock(&zcrypt_list_lock); } @@ -710,6 +714,7 @@ static int zcrypt_pendingq_count(void) pendingq_count = 0; spin_lock(&zcrypt_list_lock); + local_bh_disable(); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) @@ -719,6 +724,7 @@ static int zcrypt_pendingq_count(void) spin_unlock(&zq->queue->lock); } } + local_bh_enable(); spin_unlock(&zcrypt_list_lock); return pendingq_count; } @@ -731,6 +737,7 @@ static int zcrypt_requestq_count(void) requestq_count = 0; spin_lock(&zcrypt_list_lock); + local_bh_disable(); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) @@ -740,6 +747,7 @@ static int zcrypt_requestq_count(void) spin_unlock(&zq->queue->lock); } } + local_bh_enable(); spin_unlock(&zcrypt_list_lock); return requestq_count; } -- cgit v1.2.3-59-g8ed1b From 09762dcb623b5cff08c624250130cdcd389d5044 Mon Sep 17 00:00:00 2001 From: Jan Höppner Date: Mon, 21 Nov 2016 13:21:59 +0100 Subject: s390/dasd: Always store parameter elements in an array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the DASD driver is built into the kernel, the entire comma separated parameter list is stored as one single element in the dasd[] array, opposed to the module build where each element is stored separately in dasd[]. There is no point in doing so. Therefore, store each part of the list as single elements in dasd[] as well when built into the kernel. Also, create a define for the maximum of 256 parameters. Reviewed-by: Stefan Haberland Reviewed-by: Sebastian Ott Signed-off-by: Jan Höppner Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index dd46e96a3034..4c8eff6b1aab 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -26,6 +26,7 @@ /* This is ugly... */ #define PRINTK_HEADER "dasd_devmap:" #define DASD_BUS_ID_SIZE 20 +#define DASD_MAX_PARAMS 256 #include "dasd_int.h" @@ -76,7 +77,7 @@ EXPORT_SYMBOL_GPL(dasd_nofcx); * it is named 'dasd' to directly be filled by insmod with the comma separated * strings when running as a module. */ -static char *dasd[256]; +static char *dasd[DASD_MAX_PARAMS]; module_param_array(dasd, charp, NULL, S_IRUGO); /* @@ -104,18 +105,19 @@ dasd_hash_busid(const char *bus_id) } #ifndef MODULE -/* - * The parameter parsing functions for builtin-drivers are called - * before kmalloc works. Store the pointers to the parameters strings - * into dasd[] for later processing. - */ -static int __init -dasd_call_setup(char *str) +static int __init dasd_call_setup(char *opt) { - static int count = 0; + static int i; + char *tmp; + + while (i < DASD_MAX_PARAMS) { + tmp = strsep(&opt, ","); + if (!tmp) + break; + + dasd[i++] = tmp; + } - if (count < 256) - dasd[count++] = str; return 1; } @@ -364,10 +366,8 @@ dasd_parse_next_element( char *parsestring ) { /* * Parse parameters stored in dasd[] * The 'dasd=...' parameter allows to specify a comma separated list of - * keywords and device ranges. When the dasd driver is build into the kernel, - * the complete list will be stored as one element of the dasd[] array. - * When the dasd driver is build as a module, then the list is broken into - * it's elements and each dasd[] entry contains one element. + * keywords and device ranges. The parameters in that list will be stored as + * separate elementes in dasd[]. */ int dasd_parse(void) @@ -376,7 +376,7 @@ dasd_parse(void) char *parsestring; rc = 0; - for (i = 0; i < 256; i++) { + for (i = 0; i < DASD_MAX_PARAMS; i++) { if (dasd[i] == NULL) break; parsestring = dasd[i]; -- cgit v1.2.3-59-g8ed1b From 3b1bea012710c1a299573c7a6a0584d623e6cbcf Mon Sep 17 00:00:00 2001 From: Jan Höppner Date: Tue, 22 Nov 2016 18:11:46 +0100 Subject: s390/dasd: Improve parameter list parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function dasd_busid() still uses simple_strtoul() to convert a string to an integer value. This function is obsolete for quite some time already and should be replaced. The whole parameter parsing semantic still relies somewhat on the fact, that simple_strtoul() parses a string containing literals without complains and just returns the parsed integer value plus the residual string. kstrtoint(), however, would return -EINVAL in such a case. Since we want to get rid of simple_strtoul() and now have a nice dasd[] containing only single elements, we can clean up and simplify a few things. Replace simple_strtoul() with kstrtouint(), improve and simplify the overall parameter parsing by the following: - instead of residual strings return proper error codes - remove dasd_parse_next_element() and decide directly what sort of element is being parsed - if we parse a device or a range of devices, split that element into separate bits with a new function - remove warning about invalid ending as it doesn't apply anymore - annotate all parsing functions and data that can be freed after initialisation with __init and __initdata respectively - clean up bits and pieces while at it Reviewed-by: Stefan Haberland Reviewed-by: Sebastian Ott Signed-off-by: Jan Höppner Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 258 +++++++++++++++++++-------------------- drivers/s390/block/dasd_int.h | 2 +- 2 files changed, 125 insertions(+), 135 deletions(-) diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 4c8eff6b1aab..041bdc4429c1 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -107,7 +107,7 @@ dasd_hash_busid(const char *bus_id) #ifndef MODULE static int __init dasd_call_setup(char *opt) { - static int i; + static int i __initdata; char *tmp; while (i < DASD_MAX_PARAMS) { @@ -129,14 +129,13 @@ __setup ("dasd=", dasd_call_setup); /* * Read a device busid/devno from a string. */ -static int - -dasd_busid(char **str, int *id0, int *id1, int *devno) +static int __init dasd_busid(char *str, int *id0, int *id1, int *devno) { - int val, old_style; + unsigned int val; + char *tok; /* Interpret ipldev busid */ - if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) { + if (strncmp(DASD_IPLDEV, str, strlen(DASD_IPLDEV)) == 0) { if (ipl_info.type != IPL_TYPE_CCW) { pr_err("The IPL device is not a CCW device\n"); return -EINVAL; @@ -144,63 +143,50 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) *id0 = 0; *id1 = ipl_info.data.ccw.dev_id.ssid; *devno = ipl_info.data.ccw.dev_id.devno; - *str += strlen(DASD_IPLDEV); return 0; } - /* check for leading '0x' */ - old_style = 0; - if ((*str)[0] == '0' && (*str)[1] == 'x') { - *str += 2; - old_style = 1; - } - if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; - val = simple_strtoul(*str, str, 16); - if (old_style || (*str)[0] != '.') { + + /* Old style 0xXXXX or XXXX */ + if (!kstrtouint(str, 16, &val)) { *id0 = *id1 = 0; if (val < 0 || val > 0xffff) return -EINVAL; *devno = val; return 0; } + /* New style x.y.z busid */ - if (val < 0 || val > 0xff) + tok = strsep(&str, "."); + if (kstrtouint(tok, 16, &val) || val > 0xff) return -EINVAL; *id0 = val; - (*str)++; - if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; - val = simple_strtoul(*str, str, 16); - if (val < 0 || val > 0xff || (*str)++[0] != '.') + + tok = strsep(&str, "."); + if (kstrtouint(tok, 16, &val) || val > 0xff) return -EINVAL; *id1 = val; - if (!isxdigit((*str)[0])) /* We require at least one hex digit */ - return -EINVAL; - val = simple_strtoul(*str, str, 16); - if (val < 0 || val > 0xffff) + + tok = strsep(&str, "."); + if (kstrtouint(tok, 16, &val) || val > 0xffff) return -EINVAL; *devno = val; + return 0; } /* - * Read colon separated list of dasd features. Currently there is - * only one: "ro" for read-only devices. The default feature set - * is empty (value 0). + * Read colon separated list of dasd features. */ -static int -dasd_feature_list(char *str, char **endp) +static int __init dasd_feature_list(char *str) { int features, len, rc; + features = 0; rc = 0; - if (*str != '(') { - *endp = str; + + if (!str) return DASD_FEATURE_DEFAULT; - } - str++; - features = 0; while (1) { for (len = 0; @@ -225,15 +211,8 @@ dasd_feature_list(char *str, char **endp) break; str++; } - if (*str != ')') { - pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n"); - rc = -EINVAL; - } else - str++; - *endp = str; - if (rc != 0) - return rc; - return features; + + return rc ? : features; } /* @@ -242,48 +221,38 @@ dasd_feature_list(char *str, char **endp) * action and return a pointer to the residual string. If the first element * could not be matched to any keyword then return an error code. */ -static char * -dasd_parse_keyword( char *parsestring ) { - - char *nextcomma, *residual_str; - int length; +static int __init dasd_parse_keyword(char *keyword) +{ + int length = strlen(keyword); - nextcomma = strchr(parsestring,','); - if (nextcomma) { - length = nextcomma - parsestring; - residual_str = nextcomma + 1; - } else { - length = strlen(parsestring); - residual_str = parsestring + length; - } - if (strncmp("autodetect", parsestring, length) == 0) { + if (strncmp("autodetect", keyword, length) == 0) { dasd_autodetect = 1; pr_info("The autodetection mode has been activated\n"); - return residual_str; + return 0; } - if (strncmp("probeonly", parsestring, length) == 0) { + if (strncmp("probeonly", keyword, length) == 0) { dasd_probeonly = 1; pr_info("The probeonly mode has been activated\n"); - return residual_str; + return 0; } - if (strncmp("nopav", parsestring, length) == 0) { + if (strncmp("nopav", keyword, length) == 0) { if (MACHINE_IS_VM) pr_info("'nopav' is not supported on z/VM\n"); else { dasd_nopav = 1; pr_info("PAV support has be deactivated\n"); } - return residual_str; + return 0; } - if (strncmp("nofcx", parsestring, length) == 0) { + if (strncmp("nofcx", keyword, length) == 0) { dasd_nofcx = 1; pr_info("High Performance FICON support has been " "deactivated\n"); - return residual_str; + return 0; } - if (strncmp("fixedbuffers", parsestring, length) == 0) { + if (strncmp("fixedbuffers", keyword, length) == 0) { if (dasd_page_cache) - return residual_str; + return 0; dasd_page_cache = kmem_cache_create("dasd_page_cache", PAGE_SIZE, PAGE_SIZE, SLAB_CACHE_DMA, @@ -294,73 +263,97 @@ dasd_parse_keyword( char *parsestring ) { else DBF_EVENT(DBF_INFO, "%s", "turning on fixed buffer mode"); - return residual_str; - } - return ERR_PTR(-EINVAL); + return 0; + } + + return -EINVAL; } /* - * Try to interprete the first element on the comma separated parse string - * as a device number or a range of devices. If the interpretation is - * successful, create the matching dasd_devmap entries and return a pointer - * to the residual string. - * If interpretation fails or in case of an error, return an error code. + * Split a string of a device range into its pieces and return the from, to, and + * feature parts separately. + * e.g.: + * 0.0.1234-0.0.5678(ro:erplog) -> from: 0.0.1234 to: 0.0.5678 features: ro:erplog + * 0.0.8765(raw) -> from: 0.0.8765 to: null features: raw + * 0x4321 -> from: 0x4321 to: null features: null */ -static char * -dasd_parse_range( char *parsestring ) { +static int __init dasd_evaluate_range_param(char *range, char **from_str, + char **to_str, char **features_str) +{ + int rc = 0; + /* Do we have a range or a single device? */ + if (strchr(range, '-')) { + *from_str = strsep(&range, "-"); + *to_str = strsep(&range, "("); + *features_str = strsep(&range, ")"); + } else { + *from_str = strsep(&range, "("); + *features_str = strsep(&range, ")"); + } + + if (*features_str && !range) { + pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n"); + rc = -EINVAL; + } + + return rc; +} + +/* + * Try to interprete the range string as a device number or a range of devices. + * If the interpretation is successful, create the matching dasd_devmap entries. + * If interpretation fails or in case of an error, return an error code. + */ +static int __init dasd_parse_range(const char *range) +{ struct dasd_devmap *devmap; int from, from_id0, from_id1; int to, to_id0, to_id1; - int features, rc; - char bus_id[DASD_BUS_ID_SIZE+1], *str; - - str = parsestring; - rc = dasd_busid(&str, &from_id0, &from_id1, &from); - if (rc == 0) { - to = from; - to_id0 = from_id0; - to_id1 = from_id1; - if (*str == '-') { - str++; - rc = dasd_busid(&str, &to_id0, &to_id1, &to); + int features; + char bus_id[DASD_BUS_ID_SIZE + 1]; + char *features_str = NULL; + char *from_str = NULL; + char *to_str = NULL; + size_t len = strlen(range) + 1; + char tmp[len]; + + strlcpy(tmp, range, len); + + if (dasd_evaluate_range_param(tmp, &from_str, &to_str, &features_str)) + goto out_err; + + if (dasd_busid(from_str, &from_id0, &from_id1, &from)) + goto out_err; + + to = from; + to_id0 = from_id0; + to_id1 = from_id1; + if (to_str) { + if (dasd_busid(to_str, &to_id0, &to_id1, &to)) + goto out_err; + if (from_id0 != to_id0 || from_id1 != to_id1 || from > to) { + pr_err("%s is not a valid device range\n", range); + goto out_err; } } - if (rc == 0 && - (from_id0 != to_id0 || from_id1 != to_id1 || from > to)) - rc = -EINVAL; - if (rc) { - pr_err("%s is not a valid device range\n", parsestring); - return ERR_PTR(rc); - } - features = dasd_feature_list(str, &str); + + features = dasd_feature_list(features_str); if (features < 0) - return ERR_PTR(-EINVAL); + goto out_err; /* each device in dasd= parameter should be set initially online */ features |= DASD_FEATURE_INITIAL_ONLINE; while (from <= to) { - sprintf(bus_id, "%01x.%01x.%04x", - from_id0, from_id1, from++); + sprintf(bus_id, "%01x.%01x.%04x", from_id0, from_id1, from++); devmap = dasd_add_busid(bus_id, features); if (IS_ERR(devmap)) - return (char *)devmap; + return PTR_ERR(devmap); } - if (*str == ',') - return str + 1; - if (*str == '\0') - return str; - pr_warn("The dasd= parameter value %s has an invalid ending\n", str); - return ERR_PTR(-EINVAL); -} -static char * -dasd_parse_next_element( char *parsestring ) { - char * residual_str; - residual_str = dasd_parse_keyword(parsestring); - if (!IS_ERR(residual_str)) - return residual_str; - residual_str = dasd_parse_range(parsestring); - return residual_str; + return 0; + +out_err: + return -EINVAL; } /* @@ -369,30 +362,27 @@ dasd_parse_next_element( char *parsestring ) { * keywords and device ranges. The parameters in that list will be stored as * separate elementes in dasd[]. */ -int -dasd_parse(void) +int __init dasd_parse(void) { int rc, i; - char *parsestring; + char *cur; rc = 0; for (i = 0; i < DASD_MAX_PARAMS; i++) { - if (dasd[i] == NULL) + cur = dasd[i]; + if (!cur) break; - parsestring = dasd[i]; - /* loop over the comma separated list in the parsestring */ - while (*parsestring) { - parsestring = dasd_parse_next_element(parsestring); - if(IS_ERR(parsestring)) { - rc = PTR_ERR(parsestring); - break; - } - } - if (rc) { - DBF_EVENT(DBF_ALERT, "%s", "invalid range found"); + if (*cur == '\0') + continue; + + rc = dasd_parse_keyword(cur); + if (rc) + rc = dasd_parse_range(cur); + + if (rc) break; - } } + return rc; } diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 24be210c10e5..518dba2732d5 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -805,7 +805,7 @@ struct dasd_device *dasd_device_from_devindex(int); void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); struct dasd_device *dasd_device_from_gendisk(struct gendisk *); -int dasd_parse(void); +int dasd_parse(void) __init; int dasd_busid_known(const char *); /* externals in dasd_gendisk.c */ -- cgit v1.2.3-59-g8ed1b From 34525e1f7e8dc47834b52d19b02c94b250df6f1f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 25 Jan 2017 12:54:17 +0100 Subject: s390: store breaking event address only for program checks The principles of operations specifies that the breaking event address is stored to the address 0x110 in the prefix page only for program checks. The last branch in user space is lost as soon as a branch in kernel space is executed after e.g. an svc. This makes it impossible to accurately maintain the breaking event address for a user space process. Simplify the code, just copy the current breaking event address from 0x110 to the task structure for program checks from user space. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/entry.S | 50 ++++++++++++------------------------------------ 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 97298c58b2be..f687f168c94d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -103,8 +103,7 @@ _PIF_WORK = (_PIF_PER_TRAP) CHECK_STACK 1< Date: Wed, 25 Jan 2017 14:08:20 +0100 Subject: s390/dasd: allow 0 for path_threshold attribute Allow 0 as valid input for the path_threshold attribute to deactivate the IFCC/CCC error handling. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_devmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 041bdc4429c1..1164b51d09f3 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1518,14 +1518,12 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(device)) return -ENODEV; - if ((kstrtoul(buf, 10, &val) != 0) || - (val > DASD_THRHLD_MAX) || val == 0) { + if (kstrtoul(buf, 10, &val) != 0 || val > DASD_THRHLD_MAX) { dasd_put_device(device); return -EINVAL; } spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); - if (val) - device->path_thrhld = val; + device->path_thrhld = val; spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags); dasd_put_device(device); return count; -- cgit v1.2.3-59-g8ed1b From 2202134e48a3b50320aeb9e3dd1186833e9d7e66 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 25 Jan 2017 14:47:32 +0100 Subject: s390/dasd: check for device error pointer within state change interrupts Check if the device pointer is valid. Just a sanity check since we already are in the int handler of the device. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 0e3fdfdbd098..f3099c8cc143 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1712,8 +1712,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* check for for attention message */ if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) { device = dasd_device_from_cdev_locked(cdev); - device->discipline->check_attention(device, irb->esw.esw1.lpum); - dasd_put_device(device); + if (!IS_ERR(device)) { + device->discipline->check_attention(device, + irb->esw.esw1.lpum); + dasd_put_device(device); + } } if (!cqr) -- cgit v1.2.3-59-g8ed1b From ca732e111ff7017e79a0cbb8aa0636c6ce48eb7d Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 25 Jan 2017 16:56:41 +0100 Subject: s390/dasd: check blockdevice pointer before trying to sync blockdevice If safe offline is called for a DASD alias device a null pointer is passed to fsync_bdev. So check for existence of the blockdevice before calling fsync_bdev. Should not be a real world problem since safe offline for an alias device does not make sense and fsync_bdev can deal with a NULL pointer which it gets after successful NULL pointer dereferencing on s390. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f3099c8cc143..6fb3fd5efc11 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3601,10 +3601,11 @@ int dasd_generic_set_offline(struct ccw_device *cdev) * empty */ /* sync blockdev and partitions */ - rc = fsync_bdev(device->block->bdev); - if (rc != 0) - goto interrupted; - + if (device->block) { + rc = fsync_bdev(device->block->bdev); + if (rc != 0) + goto interrupted; + } /* schedule device tasklet and wait for completion */ dasd_schedule_device_bh(device); rc = wait_event_interruptible(shutdown_waitq, -- cgit v1.2.3-59-g8ed1b From ba21d0ea218983f269f957de267ca62fdbf96be3 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 25 Jan 2017 16:59:46 +0100 Subject: s390/dasd: correct inconsistent indenting Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ade04216c970..0f1713727d4c 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2543,8 +2543,8 @@ dasd_eckd_build_format(struct dasd_device *base, DASD_ECKD_CCW_WRITE_CKD_MT; ccw->flags = CCW_FLAG_SLI; ccw->count = 8; - ccw->cda = (__u32)(addr_t) ect; - ccw++; + ccw->cda = (__u32)(addr_t) ect; + ccw++; } } } -- cgit v1.2.3-59-g8ed1b From a63f53e34db8b49675448d03ae324f6c5bc04fe6 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Mon, 30 Jan 2017 15:52:14 +0100 Subject: s390/dcssblk: fix device size calculation in dcssblk_direct_access() Since commit dd22f551 "block: Change direct_access calling convention", the device size calculation in dcssblk_direct_access() is off-by-one. This results in bdev_direct_access() always returning -ENXIO because the returned value is not page aligned. Fix this by adding 1 to the dev_sz calculation. Fixes: dd22f551 ("block: Change direct_access calling convention") Cc: # 4.0+ Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dcssblk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9d66b4fb174b..415d10a67b7a 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -892,7 +892,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, dev_info = bdev->bd_disk->private_data; if (!dev_info) return -ENODEV; - dev_sz = dev_info->end - dev_info->start; + dev_sz = dev_info->end - dev_info->start + 1; offset = secnum * 512; *kaddr = (void *) dev_info->start + offset; *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV); -- cgit v1.2.3-59-g8ed1b From 1e4a382fdc0ba8d1a85b758c0811de3a3631085e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 21 Nov 2016 13:37:48 +0100 Subject: s390/qdio: clear DSCI prior to scanning multiple input queues For devices with multiple input queues, tiqdio_call_inq_handlers() iterates over all input queues and clears the device's DSCI during each iteration. If the DSCI is re-armed during one of the later iterations, we therefore do not scan the previous queues again. The re-arming also raises a new adapter interrupt. But its handler does not trigger a rescan for the device, as the DSCI has already been erroneously cleared. This can result in queue stalls on devices with multiple input queues. Fix it by clearing the DSCI just once, prior to scanning the queues. As the code is moved in front of the loop, we also need to access the DSCI directly (ie irq->dsci) instead of going via each queue's parent pointer to the same irq. This is not a functional change, and a follow-up patch will clean up the other users. In practice, this bug only affects CQ-enabled HiperSockets devices, ie. devices with sysfs-attribute "hsuid" set. Setting a hsuid is needed for AF_IUCV socket applications that use HiperSockets communication. Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks") Cc: # v3.2+ Reviewed-by: Ursula Braun Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_thinint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 5d06253c2a7a..30e9fbbff051 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -147,11 +147,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) struct qdio_q *q; int i; - for_each_input_queue(irq, q, i) { - if (!references_shared_dsci(irq) && - has_multiple_inq_on_dsci(irq)) - xchg(q->irq_ptr->dsci, 0); + if (!references_shared_dsci(irq) && + has_multiple_inq_on_dsci(irq)) + xchg(irq->dsci, 0); + for_each_input_queue(irq, q, i) { if (q->u.in.queue_start_poll) { /* skip if polling is enabled or already in work */ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, -- cgit v1.2.3-59-g8ed1b From 67bb323bfee7db1af047ae15a5d7f8f5a52a09a6 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 21 Nov 2016 13:34:23 +0100 Subject: s390/qdio: clean up q->irq_ptr usage In tiqdio_call_inq_handlers(), we're looping over all input queues on the *same* irq. So instead of using the queues' back pointer, we can just access the irq directly. No functional change. Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_thinint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 30e9fbbff051..90447e9611b4 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -161,11 +161,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) } /* avoid dsci clear here, done after processing */ - q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, - q->irq_ptr->int_parm); + q->u.in.queue_start_poll(irq->cdev, q->nr, + irq->int_parm); } else { - if (!shared_ind(q->irq_ptr)) - xchg(q->irq_ptr->dsci, 0); + if (!shared_ind(irq)) + xchg(irq->dsci, 0); /* * Call inbound processing but not directly -- cgit v1.2.3-59-g8ed1b From 72a01d0b6afb5862998d84c19ddc9e1c39a9588c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 21 Nov 2016 11:19:57 +0100 Subject: s390/qdio: fix up tiqdio_thinint_handler() kerneldoc Missed in commit f4eae94f7137 ("s390/airq: simplify adapter interrupt code") Signed-off-by: Julian Wiedmann Reviewed-by: Steffen Maier Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_thinint.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 90447e9611b4..8ad98a902a91 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -178,8 +178,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) /** * tiqdio_thinint_handler - thin interrupt handler for qdio - * @alsi: pointer to adapter local summary indicator - * @data: NULL + * @airq: pointer to adapter interrupt descriptor */ static void tiqdio_thinint_handler(struct airq_struct *airq) { -- cgit v1.2.3-59-g8ed1b From f83435c42ee6e4233cc07130e2cf5022b95e1d32 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 21 Nov 2016 11:34:25 +0100 Subject: s390/qdio: improve some debug prints With multiple input queues, these DBFs turned out to be not very helpful... Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 71bf9bded485..a4ad39ba3873 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -457,7 +457,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) { int new; - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %02x", count); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr, count); /* for QEBSM the ACK was already set by EQBS */ if (is_qebsm(q)) { @@ -544,7 +544,8 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) case SLSB_P_INPUT_ACK: if (q->irq_ptr->perf_stat_enabled) q->q_stats.nr_sbal_nop++; - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop:%1d %#02x", + q->nr, q->first_to_check); break; default: WARN_ON_ONCE(1); -- cgit v1.2.3-59-g8ed1b From da8fd820f389a0e29080b14c61bf5cf1d8ef5ca1 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 4 Feb 2017 11:40:36 +0100 Subject: s390: make setup_randomness work Commit bcfcbb6bae64 ("s390: add system information as device randomness") intended to add some virtual machine specific information to the randomness pool. Unfortunately it uses the page allocator before it is ready to use. In result the page allocator always returns NULL and the setup_randomness function never adds anything to the randomness pool. To fix this use memblock_alloc and memblock_free instead. Fixes: bcfcbb6bae64 ("s390: add system information as device randomness") Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 1a3388c32a83..aaef71ff7ab7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -822,10 +822,10 @@ static void __init setup_randomness(void) { struct sysinfo_3_2_2 *vmms; - vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL); - if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count) + vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE); + if (stsi(vmms, 3, 2, 2) == 0 && vmms->count) add_device_randomness(&vmms, vmms->count); - free_page((unsigned long) vmms); + memblock_free((unsigned long) vmms, PAGE_SIZE); } /* -- cgit v1.2.3-59-g8ed1b From 8676caa4fb7fc02b2c76842a0024919d0caa4b8d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sat, 4 Feb 2017 12:38:12 +0100 Subject: s390/topology: correct allocation of topology information The data stored by the STSI instruction can be up to a page in size but the memblock_virt_alloc allocation for tl_info only specifies 16 bytes. The memory after the short allocation is overwritten every time arch_update_cpu_topology is called. Fixes: 8c9105802235 "s390/numa: establish cpu to node mapping early" Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 7b2b19b0b294..2cd5f4f1013c 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -458,7 +458,7 @@ void __init topology_init_early(void) set_sched_topology(s390_topology); if (!MACHINE_HAS_TOPOLOGY) goto out; - tl_info = memblock_virt_alloc(sizeof(*tl_info), PAGE_SIZE); + tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); info = tl_info; store_topology(info); pr_info("The CPU configuration topology of the machine is: %d %d %d %d %d %d / %d\n", -- cgit v1.2.3-59-g8ed1b From ea417aa8a38bc7db929281d6dc4b671e75f51844 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 16 Nov 2016 09:48:41 +0100 Subject: s390/debug: make debug event time stamps relative to the boot TOD clock The debug features currently uses absolute TOD time stamps for the debug events. Given that the TOD clock can jump forward and backward due to STP sync checks the order of debug events can get obfuscated. Replace the absolute TOD time stamps with a delta to the IPL time stamp. On a STP sync check the TOD clock correction is added to the IPL time stamp as well to make the deltas unaffected by STP sync check. The readout of the debug feature entries will convert the deltas back to absolute time stamps based on the Unix epoch. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/timex.h | 8 -------- arch/s390/kernel/debug.c | 13 +++++++------ arch/s390/kernel/time.c | 3 +-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index de8298800722..354344dcc198 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -178,14 +178,6 @@ int get_phys_clock(unsigned long long *clock); void init_cpu_timer(void); unsigned long long monotonic_clock(void); -void tod_to_timeval(__u64 todval, struct timespec64 *xt); - -static inline -void stck_to_timespec64(unsigned long long stck, struct timespec64 *ts) -{ - tod_to_timeval(stck - TOD_UNIX_EPOCH, ts); -} - extern u64 sched_clock_base_cc; /** diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 79f8ae933520..20a5a4286368 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -866,7 +866,7 @@ static inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level, int exception) { - active->id.stck = get_tod_clock_fast(); + active->id.stck = get_tod_clock_fast() - sched_clock_base_cc; active->id.fields.cpuid = smp_processor_id(); active->caller = __builtin_return_address(0); active->id.fields.exception = exception; @@ -1455,23 +1455,24 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf) { - struct timespec64 time_spec; + unsigned long sec, usec; char *except_str; unsigned long caller; int rc = 0; unsigned int level; level = entry->id.fields.level; - stck_to_timespec64(entry->id.stck, &time_spec); + sec = (entry->id.stck >> 12) + (sched_clock_base_cc >> 12); + sec = sec - (TOD_UNIX_EPOCH >> 12); + usec = do_div(sec, USEC_PER_SEC); if (entry->id.fields.exception) except_str = "*"; else except_str = "-"; caller = (unsigned long) entry->caller; - rc += sprintf(out_buf, "%02i %011lld:%06lu %1u %1s %02i %p ", - area, (long long)time_spec.tv_sec, - time_spec.tv_nsec / 1000, level, except_str, + rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %02i %p ", + area, sec, usec, level, except_str, entry->id.fields.cpuid, (void *)caller); return rc; } diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index eebbd6adc6c5..546e513a0271 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -110,7 +110,7 @@ unsigned long long monotonic_clock(void) } EXPORT_SYMBOL(monotonic_clock); -void tod_to_timeval(__u64 todval, struct timespec64 *xt) +static void tod_to_timeval(__u64 todval, struct timespec64 *xt) { unsigned long long sec; @@ -120,7 +120,6 @@ void tod_to_timeval(__u64 todval, struct timespec64 *xt) todval -= (sec * 1000000) << 12; xt->tv_nsec = ((todval * 1000) >> 12); } -EXPORT_SYMBOL(tod_to_timeval); void clock_comparator_work(void) { -- cgit v1.2.3-59-g8ed1b From 9090f3feb3637dfdc20a5a4af88ed897b2fa894f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 24 Jan 2017 15:45:13 +0100 Subject: s390/sclp: move early printk code to drivers Move the early sclp printk code to the drivers folder where also the rest of the sclp code can be found. This way it is possible to use the sclp private header files for further cleanups. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/Makefile | 3 +- arch/s390/kernel/Makefile | 10 +- arch/s390/kernel/sclp.c | 213 ------------------------------------ drivers/s390/char/Makefile | 16 ++- drivers/s390/char/sclp_early_core.c | 213 ++++++++++++++++++++++++++++++++++++ 5 files changed, 232 insertions(+), 223 deletions(-) delete mode 100644 arch/s390/kernel/sclp.c create mode 100644 drivers/s390/char/sclp_early_core.c diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 6bd2c9022be3..f7e4c834ea24 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -19,7 +19,8 @@ KBUILD_CFLAGS += $(call cc-option,-ffreestanding) GCOV_PROFILE := n UBSAN_SANITIZE := n -OBJECTS := $(addprefix $(objtree)/arch/s390/kernel/, head.o sclp.o ebcdic.o als.o) +OBJECTS := $(addprefix $(objtree)/arch/s390/kernel/, head.o ebcdic.o als.o) +OBJECTS += $(objtree)/drivers/s390/char/sclp_early_core.o OBJECTS += $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index edbc62e04027..060ce548fe8b 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -10,31 +10,25 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) # Do not trace early setup code CFLAGS_REMOVE_als.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE) endif GCOV_PROFILE_als.o := n GCOV_PROFILE_early.o := n -GCOV_PROFILE_sclp.o := n KCOV_INSTRUMENT_als.o := n KCOV_INSTRUMENT_early.o := n -KCOV_INSTRUMENT_sclp.o := n UBSAN_SANITIZE_als.o := n UBSAN_SANITIZE_early.o := n -UBSAN_SANITIZE_sclp.o := n # -# Use -march=z900 for sclp.c and als.c to be able to print an error +# Use -march=z900 for als.c to be able to print an error # message if the kernel is started on a machine which is too old # ifneq ($(CC_FLAGS_MARCH),-march=z900) CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH) CFLAGS_als.o += -march=z900 -CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH) -CFLAGS_sclp.o += -march=z900 AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH) AFLAGS_head.o += -march=z900 endif @@ -61,7 +55,7 @@ CFLAGS_sysinfo.o += -w obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o -obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o als.o +obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o obj-y += entry.o reipl.o relocate_kernel.o diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c deleted file mode 100644 index f9c5b02d2685..000000000000 --- a/arch/s390/kernel/sclp.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright IBM Corp. 2015 - * Author(s): Martin Schwidefsky - */ -#include -#include -#include -#include -#include -#include - -#define EVTYP_VT220MSG_MASK 0x00000040 -#define EVTYP_MSG_MASK 0x40000000 - -static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data); -static bool have_vt220 __section(data); -static bool have_linemode __section(data); - -static void _sclp_wait_int(void) -{ - unsigned long psw_mask, addr, flags; - psw_t psw_ext_save, psw_wait; - union ctlreg0 cr0, cr0_new; - - raw_local_irq_save(flags); - __ctl_store(cr0.val, 0, 0); - cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; - cr0_new.lap = 0; - cr0_new.sssm = 1; - __ctl_load(cr0_new.val, 0, 0); - - psw_ext_save = S390_lowcore.external_new_psw; - psw_mask = __extract_psw(); - S390_lowcore.external_new_psw.mask = psw_mask; - psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT; - S390_lowcore.ext_int_code = 0; - - do { - asm volatile( - " larl %[addr],0f\n" - " stg %[addr],%[psw_wait_addr]\n" - " stg %[addr],%[psw_ext_addr]\n" - " lpswe %[psw_wait]\n" - "0:\n" - : [addr] "=&d" (addr), - [psw_wait_addr] "=Q" (psw_wait.addr), - [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr) - : [psw_wait] "Q" (psw_wait) - : "cc", "memory"); - } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG); - - S390_lowcore.external_new_psw = psw_ext_save; - __ctl_load(cr0.val, 0, 0); - raw_local_irq_restore(flags); -} - -static int _sclp_servc(unsigned int cmd, char *sccb) -{ - unsigned int cc; - - do { - asm volatile( - " .insn rre,0xb2200000,%1,%2\n" - " ipm %0\n" - : "=d" (cc) : "d" (cmd), "a" (sccb) - : "cc", "memory"); - cc >>= 28; - if (cc == 3) - return -EINVAL; - _sclp_wait_int(); - } while (cc != 0); - return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO; -} - -static int _sclp_setup(int disable) -{ - static unsigned char init_sccb[] = { - 0x00, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, - 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned int *masks; - int rc; - - memcpy(_sclp_work_area, init_sccb, 28); - masks = (unsigned int *)(_sclp_work_area + 12); - if (disable) - memset(masks, 0, 16); - /* SCLP write mask */ - rc = _sclp_servc(0x00780005, _sclp_work_area); - if (rc) - return rc; - have_vt220 = masks[2] & EVTYP_VT220MSG_MASK; - have_linemode = masks[2] & EVTYP_MSG_MASK; - return 0; -} - -/* Output multi-line text using SCLP Message interface. */ -static void _sclp_print_lm(const char *str, unsigned int len) -{ - static unsigned char write_head[] = { - /* sccb header */ - 0x00, 0x52, /* 0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ - /* evbuf */ - 0x00, 0x4a, /* 8 */ - 0x02, 0x00, 0x00, 0x00, /* 10 */ - /* mdb */ - 0x00, 0x44, /* 14 */ - 0x00, 0x01, /* 16 */ - 0xd4, 0xc4, 0xc2, 0x40, /* 18 */ - 0x00, 0x00, 0x00, 0x01, /* 22 */ - /* go */ - 0x00, 0x38, /* 26 */ - 0x00, 0x01, /* 28 */ - 0x00, 0x00, 0x00, 0x00, /* 30 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ - 0x00, 0x00, 0x00, 0x00, /* 50 */ - 0x00, 0x00, /* 54 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */ - 0x00, 0x00, /* 80 */ - }; - static unsigned char write_mto[] = { - /* mto */ - 0x00, 0x0a, /* 0 */ - 0x00, 0x04, /* 2 */ - 0x10, 0x00, /* 4 */ - 0x00, 0x00, 0x00, 0x00 /* 6 */ - }; - unsigned char *ptr, *end_ptr, ch; - unsigned int count, num; - - num = 0; - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - ptr = _sclp_work_area + sizeof(write_head); - end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; - do { - if (ptr + sizeof(write_mto) > end_ptr) - break; - memcpy(ptr, write_mto, sizeof(write_mto)); - for (count = sizeof(write_mto); num < len; count++) { - num++; - ch = *str++; - if (ch == 0x0a) - break; - if (ptr > end_ptr) - break; - ptr[count] = _ascebc[ch]; - } - /* Update length fields in mto, mdb, evbuf and sccb */ - *(unsigned short *) ptr = count; - *(unsigned short *)(_sclp_work_area + 14) += count; - *(unsigned short *)(_sclp_work_area + 8) += count; - *(unsigned short *)(_sclp_work_area + 0) += count; - ptr += count; - } while (num < len); - - /* SCLP write data */ - _sclp_servc(0x00760005, _sclp_work_area); -} - -/* Output multi-line text (plus a newline) using SCLP VT220 - * interface. - */ -static void _sclp_print_vt220(const char *str, unsigned int len) -{ - static unsigned char const write_head[] = { - /* sccb header */ - 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* evbuf header */ - 0x00, 0x06, - 0x1a, 0x00, 0x00, 0x00, - }; - - if (sizeof(write_head) + len >= sizeof(_sclp_work_area)) - len = sizeof(_sclp_work_area) - sizeof(write_head) - 1; - - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - memcpy(_sclp_work_area + sizeof(write_head), str, len); - _sclp_work_area[sizeof(write_head) + len] = '\n'; - - /* Update length fields in evbuf and sccb headers */ - *(unsigned short *)(_sclp_work_area + 8) += len + 1; - *(unsigned short *)(_sclp_work_area + 0) += len + 1; - - /* SCLP write data */ - (void)_sclp_servc(0x00760005, _sclp_work_area); -} - -/* Output one or more lines of text on the SCLP console (VT220 and / - * or line-mode). All lines get terminated; no need for a trailing LF. - */ -void __sclp_print_early(const char *str, unsigned int len) -{ - if (_sclp_setup(0) != 0) - return; - if (have_linemode) - _sclp_print_lm(str, len); - if (have_vt220) - _sclp_print_vt220(str, len); - _sclp_setup(1); -} - -void _sclp_print_early(const char *str) -{ - __sclp_print_early(str, strlen(str)); -} diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 41e28b23b26a..0c443e26835d 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -2,9 +2,23 @@ # S/390 character devices # +ifdef CONFIG_FUNCTION_TRACER +# Do not trace early setup code +CFLAGS_REMOVE_sclp_early_core.o = $(CC_FLAGS_FTRACE) +endif + +GCOV_PROFILE_sclp_early_core.o := n +KCOV_INSTRUMENT_sclp_early_core.o := n +UBSAN_SANITIZE_sclp_early_core.o := n + +ifneq ($(CC_FLAGS_MARCH),-march=z900) +CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_MARCH) +CFLAGS_sclp_early_core.o += -march=z900 +endif + obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ - sclp_early.o + sclp_early.o sclp_early_core.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c new file mode 100644 index 000000000000..f9c5b02d2685 --- /dev/null +++ b/drivers/s390/char/sclp_early_core.c @@ -0,0 +1,213 @@ +/* + * Copyright IBM Corp. 2015 + * Author(s): Martin Schwidefsky + */ +#include +#include +#include +#include +#include +#include + +#define EVTYP_VT220MSG_MASK 0x00000040 +#define EVTYP_MSG_MASK 0x40000000 + +static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data); +static bool have_vt220 __section(data); +static bool have_linemode __section(data); + +static void _sclp_wait_int(void) +{ + unsigned long psw_mask, addr, flags; + psw_t psw_ext_save, psw_wait; + union ctlreg0 cr0, cr0_new; + + raw_local_irq_save(flags); + __ctl_store(cr0.val, 0, 0); + cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; + cr0_new.lap = 0; + cr0_new.sssm = 1; + __ctl_load(cr0_new.val, 0, 0); + + psw_ext_save = S390_lowcore.external_new_psw; + psw_mask = __extract_psw(); + S390_lowcore.external_new_psw.mask = psw_mask; + psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT; + S390_lowcore.ext_int_code = 0; + + do { + asm volatile( + " larl %[addr],0f\n" + " stg %[addr],%[psw_wait_addr]\n" + " stg %[addr],%[psw_ext_addr]\n" + " lpswe %[psw_wait]\n" + "0:\n" + : [addr] "=&d" (addr), + [psw_wait_addr] "=Q" (psw_wait.addr), + [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr) + : [psw_wait] "Q" (psw_wait) + : "cc", "memory"); + } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG); + + S390_lowcore.external_new_psw = psw_ext_save; + __ctl_load(cr0.val, 0, 0); + raw_local_irq_restore(flags); +} + +static int _sclp_servc(unsigned int cmd, char *sccb) +{ + unsigned int cc; + + do { + asm volatile( + " .insn rre,0xb2200000,%1,%2\n" + " ipm %0\n" + : "=d" (cc) : "d" (cmd), "a" (sccb) + : "cc", "memory"); + cc >>= 28; + if (cc == 3) + return -EINVAL; + _sclp_wait_int(); + } while (cc != 0); + return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO; +} + +static int _sclp_setup(int disable) +{ + static unsigned char init_sccb[] = { + 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, + 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned int *masks; + int rc; + + memcpy(_sclp_work_area, init_sccb, 28); + masks = (unsigned int *)(_sclp_work_area + 12); + if (disable) + memset(masks, 0, 16); + /* SCLP write mask */ + rc = _sclp_servc(0x00780005, _sclp_work_area); + if (rc) + return rc; + have_vt220 = masks[2] & EVTYP_VT220MSG_MASK; + have_linemode = masks[2] & EVTYP_MSG_MASK; + return 0; +} + +/* Output multi-line text using SCLP Message interface. */ +static void _sclp_print_lm(const char *str, unsigned int len) +{ + static unsigned char write_head[] = { + /* sccb header */ + 0x00, 0x52, /* 0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ + /* evbuf */ + 0x00, 0x4a, /* 8 */ + 0x02, 0x00, 0x00, 0x00, /* 10 */ + /* mdb */ + 0x00, 0x44, /* 14 */ + 0x00, 0x01, /* 16 */ + 0xd4, 0xc4, 0xc2, 0x40, /* 18 */ + 0x00, 0x00, 0x00, 0x01, /* 22 */ + /* go */ + 0x00, 0x38, /* 26 */ + 0x00, 0x01, /* 28 */ + 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ + 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, /* 54 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */ + 0x00, 0x00, /* 80 */ + }; + static unsigned char write_mto[] = { + /* mto */ + 0x00, 0x0a, /* 0 */ + 0x00, 0x04, /* 2 */ + 0x10, 0x00, /* 4 */ + 0x00, 0x00, 0x00, 0x00 /* 6 */ + }; + unsigned char *ptr, *end_ptr, ch; + unsigned int count, num; + + num = 0; + memcpy(_sclp_work_area, write_head, sizeof(write_head)); + ptr = _sclp_work_area + sizeof(write_head); + end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; + do { + if (ptr + sizeof(write_mto) > end_ptr) + break; + memcpy(ptr, write_mto, sizeof(write_mto)); + for (count = sizeof(write_mto); num < len; count++) { + num++; + ch = *str++; + if (ch == 0x0a) + break; + if (ptr > end_ptr) + break; + ptr[count] = _ascebc[ch]; + } + /* Update length fields in mto, mdb, evbuf and sccb */ + *(unsigned short *) ptr = count; + *(unsigned short *)(_sclp_work_area + 14) += count; + *(unsigned short *)(_sclp_work_area + 8) += count; + *(unsigned short *)(_sclp_work_area + 0) += count; + ptr += count; + } while (num < len); + + /* SCLP write data */ + _sclp_servc(0x00760005, _sclp_work_area); +} + +/* Output multi-line text (plus a newline) using SCLP VT220 + * interface. + */ +static void _sclp_print_vt220(const char *str, unsigned int len) +{ + static unsigned char const write_head[] = { + /* sccb header */ + 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* evbuf header */ + 0x00, 0x06, + 0x1a, 0x00, 0x00, 0x00, + }; + + if (sizeof(write_head) + len >= sizeof(_sclp_work_area)) + len = sizeof(_sclp_work_area) - sizeof(write_head) - 1; + + memcpy(_sclp_work_area, write_head, sizeof(write_head)); + memcpy(_sclp_work_area + sizeof(write_head), str, len); + _sclp_work_area[sizeof(write_head) + len] = '\n'; + + /* Update length fields in evbuf and sccb headers */ + *(unsigned short *)(_sclp_work_area + 8) += len + 1; + *(unsigned short *)(_sclp_work_area + 0) += len + 1; + + /* SCLP write data */ + (void)_sclp_servc(0x00760005, _sclp_work_area); +} + +/* Output one or more lines of text on the SCLP console (VT220 and / + * or line-mode). All lines get terminated; no need for a trailing LF. + */ +void __sclp_print_early(const char *str, unsigned int len) +{ + if (_sclp_setup(0) != 0) + return; + if (have_linemode) + _sclp_print_lm(str, len); + if (have_vt220) + _sclp_print_vt220(str, len); + _sclp_setup(1); +} + +void _sclp_print_early(const char *str) +{ + __sclp_print_early(str, strlen(str)); +} -- cgit v1.2.3-59-g8ed1b From 76fdf1416eed264dee18aa7db3a32dcfa8572e03 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 27 Jan 2017 15:54:57 +0100 Subject: s390/sclp: disable early sclp code as soon as the base sclp driver is active Make sure the early sclp code does not generate any sclp requests anymore as soon as the base sclp driver is active. Otherwise both drivers may see unexpected requests or may miss expected interrupts. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 7 ------- drivers/s390/char/sclp.h | 7 +++++++ drivers/s390/char/sclp_early_core.c | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 272898225dbb..befc07acd3e0 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -94,13 +94,6 @@ static struct timer_list sclp_request_timer; /* Timer for queued requests. */ static struct timer_list sclp_queue_timer; -/* Internal state: is the driver initialized? */ -static volatile enum sclp_init_state_t { - sclp_init_state_uninitialized, - sclp_init_state_initializing, - sclp_init_state_initialized -} sclp_init_state = sclp_init_state_uninitialized; - /* Internal state: is a request active at the sclp? */ static volatile enum sclp_running_state_t { sclp_running_state_idle, diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index e1fc7eb043d6..0c1fa376df9e 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -211,6 +211,13 @@ int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); int sclp_sdias_init(void); void sclp_sdias_exit(void); +enum { + sclp_init_state_uninitialized, + sclp_init_state_initializing, + sclp_init_state_initialized +}; + +extern int sclp_init_state; extern int sclp_console_pages; extern int sclp_console_drop; extern unsigned long sclp_console_full; diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index f9c5b02d2685..2723ab56fb8f 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -16,6 +16,8 @@ static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data); static bool have_vt220 __section(data); static bool have_linemode __section(data); +int sclp_init_state __section(data) = sclp_init_state_uninitialized; + static void _sclp_wait_int(void) { unsigned long psw_mask, addr, flags; @@ -198,6 +200,8 @@ static void _sclp_print_vt220(const char *str, unsigned int len) */ void __sclp_print_early(const char *str, unsigned int len) { + if (sclp_init_state != sclp_init_state_uninitialized) + return; if (_sclp_setup(0) != 0) return; if (have_linemode) -- cgit v1.2.3-59-g8ed1b From d5ab7a34f9bbad54f89b812e6b0d2d898f9433db Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 24 Jan 2017 15:58:52 +0100 Subject: s390/sclp: make early sclp code readable This patch - unifies the old sclp early code and the sclp early printk code, so they can use common functions - makes sure all sclp early functions and variables have the same "sclp_early" prefix - converts the sclp early printk code into readable code by using existing data structures instead of hard coded magic arrays - splits the early sclp code into two files: sclp_early.c and sclp_early_core.c. The core file contains everything that is required by the kernel decompressor and may not call functions not contained within the core file. Otherwise the result would be a link error. - changes interrupt handling to be completely synchronous. The old early sclp code had a small window which allowed to receive several interrupts instead of exactly the single expected interrupt. This did hide a subtle potential bug, which is fixed with this large rework. - contains a couple of small cleanups. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/misc.c | 2 +- arch/s390/include/asm/sclp.h | 13 +- arch/s390/kernel/als.c | 10 +- arch/s390/kernel/early_printk.c | 2 +- arch/s390/kernel/ipl.c | 2 +- arch/s390/kernel/swsusp.S | 2 +- drivers/s390/char/sclp.c | 25 ---- drivers/s390/char/sclp.h | 34 ++++- drivers/s390/char/sclp_early.c | 178 ++++++++--------------- drivers/s390/char/sclp_early_core.c | 271 ++++++++++++++++++------------------ 10 files changed, 244 insertions(+), 295 deletions(-) diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 8515dd5a5663..fa95041fa9f6 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -66,7 +66,7 @@ static unsigned long free_mem_end_ptr; static int puts(const char *s) { - _sclp_print_early(s); + sclp_early_printk(s); return 0; } diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 415eaace3f1b..ace3bd315438 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -101,7 +101,12 @@ struct zpci_report_error_header { u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ } __packed; -int _sclp_get_core_info_early(struct sclp_core_info *info); +int sclp_early_get_core_info(struct sclp_core_info *info); +void sclp_early_get_ipl_info(struct sclp_ipl_info *info); +void sclp_early_detect(void); +void sclp_early_printk(const char *s); +void __sclp_early_printk(const char *s, unsigned int len); + int _sclp_get_core_info(struct sclp_core_info *info); int sclp_core_configure(u8 core); int sclp_core_deconfigure(u8 core); @@ -110,21 +115,17 @@ int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_chp_configure(struct chp_id chpid); int sclp_chp_deconfigure(struct chp_id chpid); int sclp_chp_read_info(struct sclp_chp_info *info); -void sclp_get_ipl_info(struct sclp_ipl_info *info); int sclp_pci_configure(u32 fid); int sclp_pci_deconfigure(u32 fid); int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid); int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); -void sclp_early_detect(void); -void _sclp_print_early(const char *); -void __sclp_print_early(const char *s, unsigned int len); void sclp_ocf_cpc_name_copy(char *dst); static inline int sclp_get_core_info(struct sclp_core_info *info, int early) { if (early) - return _sclp_get_core_info_early(info); + return sclp_early_get_core_info(info); return _sclp_get_core_info(info); } diff --git a/arch/s390/kernel/als.c b/arch/s390/kernel/als.c index a16e9d1bf9e3..0b3a06f05f90 100644 --- a/arch/s390/kernel/als.c +++ b/arch/s390/kernel/als.c @@ -41,7 +41,7 @@ static void __init print_machine_type(void) get_cpu_id(&id); u16_to_hex(type_str, id.machine); strcat(mach_str, type_str); - _sclp_print_early(mach_str); + sclp_early_printk(mach_str); } static void __init u16_to_decimal(char *str, u16 val) @@ -79,7 +79,7 @@ static void __init print_missing_facilities(void) * z/VM adds a four character prefix. */ if (strlen(als_str) > 70) { - _sclp_print_early(als_str); + sclp_early_printk(als_str); *als_str = '\0'; } u16_to_decimal(val_str, i * BITS_PER_LONG + j); @@ -87,13 +87,13 @@ static void __init print_missing_facilities(void) first = 0; } } - _sclp_print_early(als_str); - _sclp_print_early("See Principles of Operations for facility bits"); + sclp_early_printk(als_str); + sclp_early_printk("See Principles of Operations for facility bits"); } static void __init facility_mismatch(void) { - _sclp_print_early("The Linux kernel requires more recent processor hardware"); + sclp_early_printk("The Linux kernel requires more recent processor hardware"); print_machine_type(); print_missing_facilities(); disabled_wait(0x8badcccc); diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c index 54a4dc582b81..819cb15c67e8 100644 --- a/arch/s390/kernel/early_printk.c +++ b/arch/s390/kernel/early_printk.c @@ -9,7 +9,7 @@ static void sclp_early_write(struct console *con, const char *s, unsigned int len) { - __sclp_print_early(s, len); + __sclp_early_printk(s, len); } static struct console sclp_early_console = { diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2c6ddced5394..5b91308f6117 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -1864,7 +1864,7 @@ static int __init s390_ipl_init(void) { char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; - sclp_get_ipl_info(&sclp_ipl_info); + sclp_early_get_ipl_info(&sclp_ipl_info); /* * Fix loadparm: There are systems where the (SCSI) LOADPARM * returned by read SCP info is invalid (contains EBCDIC blanks) diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S index 1ff21f05d7dd..6c56fb89f553 100644 --- a/arch/s390/kernel/swsusp.S +++ b/arch/s390/kernel/swsusp.S @@ -196,7 +196,7 @@ pgm_check_entry: larl %r15,init_thread_union ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) larl %r2,.Lpanic_string - larl %r3,_sclp_print_early + larl %r3,sclp_early_printk lghi %r1,0 sam31 sigp %r1,%r0,SIGP_SET_ARCHITECTURE diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index befc07acd3e0..9c471ea1b99c 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -140,31 +140,6 @@ static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); -/* Perform service call. Return 0 on success, non-zero otherwise. */ -int -sclp_service_call(sclp_cmdw_t command, void *sccb) -{ - int cc = 4; /* Initialize for program check handling */ - - asm volatile( - "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ - "1: ipm %0\n" - " srl %0,28\n" - "2:\n" - EX_TABLE(0b, 2b) - EX_TABLE(1b, 2b) - : "+&d" (cc) : "d" (command), "a" (__pa(sccb)) - : "cc", "memory"); - if (cc == 4) - return -EINVAL; - if (cc == 3) - return -EIO; - if (cc == 2) - return -EBUSY; - return 0; -} - - static void __sclp_queue_read_req(void) { diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 0c1fa376df9e..78d5f542d979 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -204,7 +204,6 @@ void sclp_unregister(struct sclp_register *reg); int sclp_remove_processed(struct sccb_header *sccb); int sclp_deactivate(void); int sclp_reactivate(void); -int sclp_service_call(sclp_cmdw_t command, void *sccb); int sclp_sync_request(sclp_cmdw_t command, void *sccb); int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); @@ -222,8 +221,41 @@ extern int sclp_console_pages; extern int sclp_console_drop; extern unsigned long sclp_console_full; +extern char sclp_early_sccb[PAGE_SIZE]; + +void sclp_early_wait_irq(void); +int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb); +int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); +unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); +int sclp_early_set_event_mask(struct init_sccb *sccb, + unsigned long receive_mask, + unsigned long send_mask); + /* useful inlines */ +/* Perform service call. Return 0 on success, non-zero otherwise. */ +static inline int sclp_service_call(sclp_cmdw_t command, void *sccb) +{ + int cc = 4; /* Initialize for program check handling */ + + asm volatile( + "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ + "1: ipm %0\n" + " srl %0,28\n" + "2:\n" + EX_TABLE(0b, 2b) + EX_TABLE(1b, 2b) + : "+&d" (cc) : "d" (command), "a" ((unsigned long)sccb) + : "cc", "memory"); + if (cc == 4) + return -EINVAL; + if (cc == 3) + return -EIO; + if (cc == 2) + return -EBUSY; + return 0; +} + /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ /* translate single character from ASCII to EBCDIC */ static inline unsigned char diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index f8e46c22e641..2f9e50379e64 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -55,31 +55,12 @@ struct read_info_sccb { u8 _pad_128[4096 - 128]; /* 128-4095 */ } __packed __aligned(PAGE_SIZE); -static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; static struct sclp_ipl_info sclp_ipl_info; struct sclp_info sclp; EXPORT_SYMBOL(sclp); -static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) -{ - int rc; - - __ctl_set_bit(0, 9); - rc = sclp_service_call(cmd, sccb); - if (rc) - goto out; - __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | - PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT); - local_irq_disable(); -out: - /* Contents of the sccb might have changed. */ - barrier(); - __ctl_clear_bit(0, 9); - return rc; -} - -static int __init sclp_read_info_early(struct read_info_sccb *sccb) +static int __init sclp_early_read_info(struct read_info_sccb *sccb) { int rc, i; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, @@ -91,7 +72,7 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) sccb->header.length = sizeof(*sccb); sccb->header.function_code = 0x80; sccb->header.control_mask[2] = 0x80; - rc = sclp_cmd_sync_early(commands[i], sccb); + rc = sclp_early_cmd_sync(commands[i], sccb); } while (rc == -EBUSY); if (rc) @@ -104,12 +85,12 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) return -EIO; } -static void __init sclp_facilities_detect(struct read_info_sccb *sccb) +static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) { struct sclp_core_entry *cpue; u16 boot_cpu_address, cpu; - if (sclp_read_info_early(sccb)) + if (sclp_early_read_info(sccb)) return; sclp.facilities = sccb->facilities; @@ -172,59 +153,19 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) } /* - * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. The sclp_facilities_detect() function retrieves + * This function will be called after sclp_early_facilities_detect(), which gets + * called from early.c code. The sclp_early_facilities_detect() function retrieves * and saves the IPL information. */ -void __init sclp_get_ipl_info(struct sclp_ipl_info *info) +void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info) { *info = sclp_ipl_info; } -static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb) -{ - int rc; +static struct sclp_core_info sclp_early_core_info __initdata; +static int sclp_early_core_info_valid __initdata; - do { - rc = sclp_cmd_sync_early(cmd, sccb); - } while (rc == -EBUSY); - - if (rc) - return -EIO; - if (((struct sccb_header *) sccb)->response_code != 0x0020) - return -EIO; - return 0; -} - -static void __init sccb_init_eq_size(struct sdias_sccb *sccb) -{ - memset(sccb, 0, sizeof(*sccb)); - - sccb->hdr.length = sizeof(*sccb); - sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf); - sccb->evbuf.hdr.type = EVTYP_SDIAS; - sccb->evbuf.event_qual = SDIAS_EQ_SIZE; - sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP; - sccb->evbuf.event_id = 4712; - sccb->evbuf.dbs = 1; -} - -static int __init sclp_set_event_mask(struct init_sccb *sccb, - unsigned long receive_mask, - unsigned long send_mask) -{ - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); - sccb->receive_mask = receive_mask; - sccb->send_mask = send_mask; - return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); -} - -static struct sclp_core_info sclp_core_info_early __initdata; -static int sclp_core_info_early_valid __initdata; - -static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb) +static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb) { int rc; @@ -233,80 +174,76 @@ static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb) memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); do { - rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb); + rc = sclp_early_cmd_sync(SCLP_CMDW_READ_CPU_INFO, sccb); } while (rc == -EBUSY); if (rc) return; if (sccb->header.response_code != 0x0010) return; - sclp_fill_core_info(&sclp_core_info_early, sccb); - sclp_core_info_early_valid = 1; + sclp_fill_core_info(&sclp_early_core_info, sccb); + sclp_early_core_info_valid = 1; } -int __init _sclp_get_core_info_early(struct sclp_core_info *info) +int __init sclp_early_get_core_info(struct sclp_core_info *info) { - if (!sclp_core_info_early_valid) + if (!sclp_early_core_info_valid) return -EIO; - *info = sclp_core_info_early; + *info = sclp_early_core_info; return 0; } -static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) +static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb) { - sccb_init_eq_size(sccb); - if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) + memset(sccb, 0, sizeof(*sccb)); + sccb->hdr.length = sizeof(*sccb); + sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf); + sccb->evbuf.hdr.type = EVTYP_SDIAS; + sccb->evbuf.event_qual = SDIAS_EQ_SIZE; + sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP; + sccb->evbuf.event_id = 4712; + sccb->evbuf.dbs = 1; + if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) return -EIO; if (sccb->evbuf.blk_cnt == 0) return 0; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; } -static long __init sclp_hsa_copy_wait(struct sccb_header *sccb) +static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb) { memset(sccb, 0, PAGE_SIZE); - sccb->length = PAGE_SIZE; - if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb)) + sccb->hdr.length = PAGE_SIZE; + if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb)) return -EIO; - if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0) + if (sccb->evbuf.blk_cnt == 0) return 0; - return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE; + return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; } -static void __init sclp_hsa_size_detect(void *sccb) +static void __init sclp_early_hsa_size_detect(void *sccb) { - long size; + unsigned long flags; + long size = -EIO; - /* First try synchronous interface (LPAR) */ - if (sclp_set_event_mask(sccb, 0, 0x40000010)) - return; - size = sclp_hsa_size_init(sccb); - if (size < 0) - return; - if (size != 0) + raw_local_irq_save(flags); + if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK)) goto out; - /* Then try asynchronous interface (z/VM) */ - if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010)) - return; - size = sclp_hsa_size_init(sccb); - if (size < 0) - return; - size = sclp_hsa_copy_wait(sccb); - if (size < 0) - return; + size = sclp_early_hsa_size_init(sccb); + /* First check for synchronous response (LPAR) */ + if (size) + goto out_mask; + if (!(S390_lowcore.ext_params & 1)) + sclp_early_wait_irq(); + size = sclp_early_hsa_copy_wait(sccb); +out_mask: + sclp_early_set_event_mask(sccb, 0, 0); out: - sclp.hsa_size = size; -} - -static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb) -{ - if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) - return 0; - if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) - return 0; - return 1; + raw_local_irq_restore(flags); + if (size > 0) + sclp.hsa_size = size; } -static void __init sclp_console_detect(struct init_sccb *sccb) +static void __init sclp_early_console_detect(struct init_sccb *sccb) { if (sccb->header.response_code != 0x20) return; @@ -314,21 +251,22 @@ static void __init sclp_console_detect(struct init_sccb *sccb) if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) sclp.has_vt220 = 1; - if (sclp_con_check_linemode(sccb)) + if (sclp_early_con_check_linemode(sccb)) sclp.has_linemode = 1; } void __init sclp_early_detect(void) { - void *sccb = &sccb_early; + void *sccb = &sclp_early_sccb; - sclp_facilities_detect(sccb); - sclp_init_core_info_early(sccb); - sclp_hsa_size_detect(sccb); + sclp_early_facilities_detect(sccb); + sclp_early_init_core_info(sccb); + sclp_early_hsa_size_detect(sccb); - /* Turn off SCLP event notifications. Also save remote masks in the + /* + * Turn off SCLP event notifications. Also save remote masks in the * sccb. These are sufficient to detect sclp console capabilities. */ - sclp_set_event_mask(sccb, 0, 0); - sclp_console_detect(sccb); + sclp_early_set_event_mask(sccb, 0, 0); + sclp_early_console_detect(sccb); } diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 2723ab56fb8f..97f4c84d6635 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -2,29 +2,24 @@ * Copyright IBM Corp. 2015 * Author(s): Martin Schwidefsky */ + #include +#include +#include #include #include -#include -#include -#include - -#define EVTYP_VT220MSG_MASK 0x00000040 -#define EVTYP_MSG_MASK 0x40000000 - -static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data); -static bool have_vt220 __section(data); -static bool have_linemode __section(data); +#include "sclp.h" +#include "sclp_rw.h" +char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data); int sclp_init_state __section(data) = sclp_init_state_uninitialized; -static void _sclp_wait_int(void) +void sclp_early_wait_irq(void) { - unsigned long psw_mask, addr, flags; + unsigned long psw_mask, addr; psw_t psw_ext_save, psw_wait; union ctlreg0 cr0, cr0_new; - raw_local_irq_save(flags); __ctl_store(cr0.val, 0, 0); cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; cr0_new.lap = 0; @@ -53,165 +48,173 @@ static void _sclp_wait_int(void) S390_lowcore.external_new_psw = psw_ext_save; __ctl_load(cr0.val, 0, 0); - raw_local_irq_restore(flags); } -static int _sclp_servc(unsigned int cmd, char *sccb) +int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb) { - unsigned int cc; + unsigned long flags; + int rc; - do { - asm volatile( - " .insn rre,0xb2200000,%1,%2\n" - " ipm %0\n" - : "=d" (cc) : "d" (cmd), "a" (sccb) - : "cc", "memory"); - cc >>= 28; - if (cc == 3) - return -EINVAL; - _sclp_wait_int(); - } while (cc != 0); - return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO; + raw_local_irq_save(flags); + rc = sclp_service_call(cmd, sccb); + if (rc) + goto out; + sclp_early_wait_irq(); +out: + raw_local_irq_restore(flags); + return rc; } -static int _sclp_setup(int disable) +int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) { - static unsigned char init_sccb[] = { - 0x00, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, - 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned int *masks; int rc; - memcpy(_sclp_work_area, init_sccb, 28); - masks = (unsigned int *)(_sclp_work_area + 12); - if (disable) - memset(masks, 0, 16); - /* SCLP write mask */ - rc = _sclp_servc(0x00780005, _sclp_work_area); + do { + rc = sclp_early_cmd_sync(cmd, sccb); + } while (rc == -EBUSY); if (rc) - return rc; - have_vt220 = masks[2] & EVTYP_VT220MSG_MASK; - have_linemode = masks[2] & EVTYP_MSG_MASK; + return -EIO; + if (((struct sccb_header *) sccb)->response_code != 0x0020) + return -EIO; return 0; } +struct write_sccb { + struct sccb_header header; + struct msg_buf msg; +} __packed; + /* Output multi-line text using SCLP Message interface. */ -static void _sclp_print_lm(const char *str, unsigned int len) +static void sclp_early_print_lm(const char *str, unsigned int len) { - static unsigned char write_head[] = { - /* sccb header */ - 0x00, 0x52, /* 0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ - /* evbuf */ - 0x00, 0x4a, /* 8 */ - 0x02, 0x00, 0x00, 0x00, /* 10 */ - /* mdb */ - 0x00, 0x44, /* 14 */ - 0x00, 0x01, /* 16 */ - 0xd4, 0xc4, 0xc2, 0x40, /* 18 */ - 0x00, 0x00, 0x00, 0x01, /* 22 */ - /* go */ - 0x00, 0x38, /* 26 */ - 0x00, 0x01, /* 28 */ - 0x00, 0x00, 0x00, 0x00, /* 30 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ - 0x00, 0x00, 0x00, 0x00, /* 50 */ - 0x00, 0x00, /* 54 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */ - 0x00, 0x00, /* 80 */ - }; - static unsigned char write_mto[] = { - /* mto */ - 0x00, 0x0a, /* 0 */ - 0x00, 0x04, /* 2 */ - 0x10, 0x00, /* 4 */ - 0x00, 0x00, 0x00, 0x00 /* 6 */ - }; - unsigned char *ptr, *end_ptr, ch; - unsigned int count, num; - - num = 0; - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - ptr = _sclp_work_area + sizeof(write_head); - end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; + unsigned char *ptr, *end, ch; + unsigned int count, offset; + struct write_sccb *sccb; + struct msg_buf *msg; + struct mdb *mdb; + struct mto *mto; + struct go *go; + + sccb = (struct write_sccb *) &sclp_early_sccb; + end = (unsigned char *) sccb + sizeof(sclp_early_sccb) - 1; + memset(sccb, 0, sizeof(*sccb)); + ptr = (unsigned char *) &sccb->msg.mdb.mto; + offset = 0; do { - if (ptr + sizeof(write_mto) > end_ptr) - break; - memcpy(ptr, write_mto, sizeof(write_mto)); - for (count = sizeof(write_mto); num < len; count++) { - num++; - ch = *str++; - if (ch == 0x0a) - break; - if (ptr > end_ptr) + for (count = sizeof(*mto); offset < len; count++) { + ch = str[offset++]; + if ((ch == 0x0a) || (ptr + count > end)) break; ptr[count] = _ascebc[ch]; } - /* Update length fields in mto, mdb, evbuf and sccb */ - *(unsigned short *) ptr = count; - *(unsigned short *)(_sclp_work_area + 14) += count; - *(unsigned short *)(_sclp_work_area + 8) += count; - *(unsigned short *)(_sclp_work_area + 0) += count; + mto = (struct mto *) ptr; + memset(mto, 0, sizeof(*mto)); + mto->length = count; + mto->type = 4; + mto->line_type_flags = LNTPFLGS_ENDTEXT; ptr += count; - } while (num < len); - - /* SCLP write data */ - _sclp_servc(0x00760005, _sclp_work_area); + } while ((offset < len) && (ptr + sizeof(*mto) <= end)); + len = ptr - (unsigned char *) sccb; + sccb->header.length = len - offsetof(struct write_sccb, header); + msg = &sccb->msg; + msg->header.type = EVTYP_MSG; + msg->header.length = len - offsetof(struct write_sccb, msg.header); + mdb = &msg->mdb; + mdb->header.type = 1; + mdb->header.tag = 0xD4C4C240; + mdb->header.revision_code = 1; + mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header); + go = &mdb->go; + go->length = sizeof(*go); + go->type = 1; + sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); } +struct vt220_sccb { + struct sccb_header header; + struct { + struct evbuf_header header; + char data[]; + } msg; +} __packed; + /* Output multi-line text (plus a newline) using SCLP VT220 * interface. */ -static void _sclp_print_vt220(const char *str, unsigned int len) +static void sclp_early_print_vt220(const char *str, unsigned int len) +{ + struct vt220_sccb *sccb; + + sccb = (struct vt220_sccb *) &sclp_early_sccb; + if (sizeof(*sccb) + len >= sizeof(sclp_early_sccb)) + len = sizeof(sclp_early_sccb) - sizeof(*sccb) - 1; + memset(sccb, 0, sizeof(*sccb)); + memcpy(&sccb->msg.data, str, len); + sccb->msg.data[len] = '\n'; + sccb->header.length = sizeof(*sccb) + len + 1; + sccb->msg.header.length = sizeof(sccb->msg) + len + 1; + sccb->msg.header.type = EVTYP_VT220MSG; + sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); +} + +int sclp_early_set_event_mask(struct init_sccb *sccb, + unsigned long receive_mask, + unsigned long send_mask) +{ + memset(sccb, 0, sizeof(*sccb)); + sccb->header.length = sizeof(*sccb); + sccb->mask_length = sizeof(sccb_mask_t); + sccb->receive_mask = receive_mask; + sccb->send_mask = send_mask; + return sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb); +} + +unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) { - static unsigned char const write_head[] = { - /* sccb header */ - 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* evbuf header */ - 0x00, 0x06, - 0x1a, 0x00, 0x00, 0x00, - }; - - if (sizeof(write_head) + len >= sizeof(_sclp_work_area)) - len = sizeof(_sclp_work_area) - sizeof(write_head) - 1; - - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - memcpy(_sclp_work_area + sizeof(write_head), str, len); - _sclp_work_area[sizeof(write_head) + len] = '\n'; - - /* Update length fields in evbuf and sccb headers */ - *(unsigned short *)(_sclp_work_area + 8) += len + 1; - *(unsigned short *)(_sclp_work_area + 0) += len + 1; - - /* SCLP write data */ - (void)_sclp_servc(0x00760005, _sclp_work_area); + if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) + return 0; + if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) + return 0; + return 1; +} + +static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) +{ + unsigned long receive_mask, send_mask; + struct init_sccb *sccb; + int rc; + + *have_linemode = *have_vt220 = 0; + sccb = (struct init_sccb *) &sclp_early_sccb; + receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; + send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK; + rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask); + if (rc) + return rc; + *have_linemode = sclp_early_con_check_linemode(sccb); + *have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK; + return rc; } /* Output one or more lines of text on the SCLP console (VT220 and / * or line-mode). All lines get terminated; no need for a trailing LF. */ -void __sclp_print_early(const char *str, unsigned int len) +void __sclp_early_printk(const char *str, unsigned int len) { + int have_linemode, have_vt220; + if (sclp_init_state != sclp_init_state_uninitialized) return; - if (_sclp_setup(0) != 0) + if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0) return; if (have_linemode) - _sclp_print_lm(str, len); + sclp_early_print_lm(str, len); if (have_vt220) - _sclp_print_vt220(str, len); - _sclp_setup(1); + sclp_early_print_vt220(str, len); + sclp_early_setup(1, &have_linemode, &have_vt220); } -void _sclp_print_early(const char *str) +void sclp_early_printk(const char *str) { - __sclp_print_early(str, strlen(str)); + __sclp_early_printk(str, strlen(str)); } -- cgit v1.2.3-59-g8ed1b From 02407baaebdef86571e4e939ddbd3b32d9b5d389 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 2 Feb 2017 10:33:20 +0100 Subject: s390/sclp: don't add new lines to each printed string The early vt220 sclp printk code added an extra new line to each printed multi-line text. If used for the early sclp console this will lead to numerous extra new lines. Therefore get rid of this semantic and require that each to be printed string contains a line feed character if a new line is wanted. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/als.c | 7 +++++-- arch/s390/kernel/swsusp.S | 2 +- drivers/s390/char/sclp_early_core.c | 16 +++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/s390/kernel/als.c b/arch/s390/kernel/als.c index 0b3a06f05f90..14769eb52a33 100644 --- a/arch/s390/kernel/als.c +++ b/arch/s390/kernel/als.c @@ -41,6 +41,7 @@ static void __init print_machine_type(void) get_cpu_id(&id); u16_to_hex(type_str, id.machine); strcat(mach_str, type_str); + strcat(mach_str, "\n"); sclp_early_printk(mach_str); } @@ -79,6 +80,7 @@ static void __init print_missing_facilities(void) * z/VM adds a four character prefix. */ if (strlen(als_str) > 70) { + strcat(als_str, "\n"); sclp_early_printk(als_str); *als_str = '\0'; } @@ -87,13 +89,14 @@ static void __init print_missing_facilities(void) first = 0; } } + strcat(als_str, "\n"); sclp_early_printk(als_str); - sclp_early_printk("See Principles of Operations for facility bits"); + sclp_early_printk("See Principles of Operations for facility bits\n"); } static void __init facility_mismatch(void) { - sclp_early_printk("The Linux kernel requires more recent processor hardware"); + sclp_early_printk("The Linux kernel requires more recent processor hardware\n"); print_machine_type(); print_missing_facilities(); disabled_wait(0x8badcccc); diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S index 6c56fb89f553..6bebc935e9c2 100644 --- a/arch/s390/kernel/swsusp.S +++ b/arch/s390/kernel/swsusp.S @@ -273,7 +273,7 @@ restore_registers: .Ldisabled_wait_31: .long 0x000a0000,0x00000000 .Lpanic_string: - .asciz "Resume not possible because suspend CPU is no longer available" + .asciz "Resume not possible because suspend CPU is no longer available\n" .align 8 .Lrestart_diag308_psw: .long 0x00080000,0x80000000 diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 97f4c84d6635..cc3ad8c69a7a 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -138,21 +138,18 @@ struct vt220_sccb { } msg; } __packed; -/* Output multi-line text (plus a newline) using SCLP VT220 - * interface. - */ +/* Output multi-line text using SCLP VT220 interface. */ static void sclp_early_print_vt220(const char *str, unsigned int len) { struct vt220_sccb *sccb; sccb = (struct vt220_sccb *) &sclp_early_sccb; if (sizeof(*sccb) + len >= sizeof(sclp_early_sccb)) - len = sizeof(sclp_early_sccb) - sizeof(*sccb) - 1; + len = sizeof(sclp_early_sccb) - sizeof(*sccb); memset(sccb, 0, sizeof(*sccb)); memcpy(&sccb->msg.data, str, len); - sccb->msg.data[len] = '\n'; - sccb->header.length = sizeof(*sccb) + len + 1; - sccb->msg.header.length = sizeof(sccb->msg) + len + 1; + sccb->header.length = sizeof(*sccb) + len; + sccb->msg.header.length = sizeof(sccb->msg) + len; sccb->msg.header.type = EVTYP_VT220MSG; sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); } @@ -196,8 +193,9 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) return rc; } -/* Output one or more lines of text on the SCLP console (VT220 and / - * or line-mode). All lines get terminated; no need for a trailing LF. +/* + * Output one or more lines of text on the SCLP console (VT220 and / + * or line-mode). */ void __sclp_early_printk(const char *str, unsigned int len) { -- cgit v1.2.3-59-g8ed1b From f694bb3a36a8113addd31817e4b5aca42326353d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 2 Feb 2017 12:33:03 +0100 Subject: s390/sclp: get rid of common response code handling Get rid of common response code handling. Each command requires its own response code handling anyway. Also the retry in case of -EBUSY does not work and can be simply removed. Reviewed-by: Peter Oberparleiter Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.h | 1 - drivers/s390/char/sclp_early.c | 27 +++++++++++---------------- drivers/s390/char/sclp_early_core.c | 22 ++++++---------------- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 78d5f542d979..53b5d1b9761a 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -224,7 +224,6 @@ extern unsigned long sclp_console_full; extern char sclp_early_sccb[PAGE_SIZE]; void sclp_early_wait_irq(void); -int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb); int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); int sclp_early_set_event_mask(struct init_sccb *sccb, diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 2f9e50379e64..519ec1787117 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -62,20 +62,16 @@ EXPORT_SYMBOL(sclp); static int __init sclp_early_read_info(struct read_info_sccb *sccb) { - int rc, i; + int i; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, SCLP_CMDW_READ_SCP_INFO}; for (i = 0; i < ARRAY_SIZE(commands); i++) { - do { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->header.function_code = 0x80; - sccb->header.control_mask[2] = 0x80; - rc = sclp_early_cmd_sync(commands[i], sccb); - } while (rc == -EBUSY); - - if (rc) + memset(sccb, 0, sizeof(*sccb)); + sccb->header.length = sizeof(*sccb); + sccb->header.function_code = 0x80; + sccb->header.control_mask[2] = 0x80; + if (sclp_early_cmd(commands[i], sccb)) break; if (sccb->header.response_code == 0x10) return 0; @@ -167,16 +163,11 @@ static int sclp_early_core_info_valid __initdata; static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb) { - int rc; - if (!SCLP_HAS_CPU_INFO) return; memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); - do { - rc = sclp_early_cmd_sync(SCLP_CMDW_READ_CPU_INFO, sccb); - } while (rc == -EBUSY); - if (rc) + if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb)) return; if (sccb->header.response_code != 0x0010) return; @@ -204,6 +195,8 @@ static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb) sccb->evbuf.dbs = 1; if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) return -EIO; + if (sccb->hdr.response_code != 0x20) + return -EIO; if (sccb->evbuf.blk_cnt == 0) return 0; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; @@ -215,6 +208,8 @@ static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb) sccb->hdr.length = PAGE_SIZE; if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb)) return -EIO; + if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220)) + return -EIO; if (sccb->evbuf.blk_cnt == 0) return 0; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index cc3ad8c69a7a..5029cc87e80f 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -50,7 +50,7 @@ void sclp_early_wait_irq(void) __ctl_load(cr0.val, 0, 0); } -int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb) +int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) { unsigned long flags; int rc; @@ -65,20 +65,6 @@ out: return rc; } -int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) -{ - int rc; - - do { - rc = sclp_early_cmd_sync(cmd, sccb); - } while (rc == -EBUSY); - if (rc) - return -EIO; - if (((struct sccb_header *) sccb)->response_code != 0x0020) - return -EIO; - return 0; -} - struct write_sccb { struct sccb_header header; struct msg_buf msg; @@ -163,7 +149,11 @@ int sclp_early_set_event_mask(struct init_sccb *sccb, sccb->mask_length = sizeof(sccb_mask_t); sccb->receive_mask = receive_mask; sccb->send_mask = send_mask; - return sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb); + if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) + return -EIO; + if (sccb->header.response_code != 0x20) + return -EIO; + return 0; } unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) -- cgit v1.2.3-59-g8ed1b From 4920e3cf77347d7d7373552d4839e8d832321313 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sun, 5 Feb 2017 23:03:18 +0100 Subject: s390: use correct input data address for setup_randomness The current implementation of setup_randomness uses the stack address and therefore the pointer to the SYSIB 3.2.2 block as input data address. Furthermore the length of the input data is the number of virtual-machine description blocks which is typically one. This means that typically a single zero byte is fed to add_device_randomness. Fix both of these and use the address of the first virtual machine description block as input data address and also use the correct length. Fixes: bcfcbb6bae64 ("s390: add system information as device randomness") Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index aaef71ff7ab7..f92c78277680 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -824,7 +824,7 @@ static void __init setup_randomness(void) vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE); if (stsi(vmms, 3, 2, 2) == 0 && vmms->count) - add_device_randomness(&vmms, vmms->count); + add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count); memblock_free((unsigned long) vmms, PAGE_SIZE); } -- cgit v1.2.3-59-g8ed1b From 2583b848cad049cf5f3f0a03af8b140668b376f3 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 31 Mar 2016 09:55:17 +0200 Subject: s390: report new vector facilities Add hardware capability bits and feature tags to /proc/cpuinfo for the "Vector Packed Decimal Facility" (tag "vxd" / hwcap bit 2^12) and the "Vector Enhancements Facility 1" (tag "vxe" / hwcap bit 2^13). Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/elf.h | 2 ++ arch/s390/kernel/processor.c | 2 +- arch/s390/kernel/setup.c | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index f4381e1fb19e..83aaefed2a7b 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -103,6 +103,8 @@ #define HWCAP_S390_HIGH_GPRS 512 #define HWCAP_S390_TE 1024 #define HWCAP_S390_VXRS 2048 +#define HWCAP_S390_VXRS_BCD 4096 +#define HWCAP_S390_VXRS_EXT 8192 /* Internal bits, not exposed via elf */ #define HWCAP_INT_SIE 1UL diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 8733b07b5691..21004aaac69b 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -92,7 +92,7 @@ static void show_cpu_summary(struct seq_file *m, void *v) { static const char *hwcap_str[] = { "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", - "edat", "etf3eh", "highgprs", "te", "vx" + "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe" }; static const char * const int_hwcap_str[] = { "sie" diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f92c78277680..8d59f20a658f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -769,8 +769,14 @@ static int __init setup_hwcaps(void) * can be disabled with the "novx" parameter. Use MACHINE_HAS_VX * instead of facility bit 129. */ - if (MACHINE_HAS_VX) + if (MACHINE_HAS_VX) { elf_hwcap |= HWCAP_S390_VXRS; + if (test_facility(134)) + elf_hwcap |= HWCAP_S390_VXRS_EXT; + if (test_facility(135)) + elf_hwcap |= HWCAP_S390_VXRS_BCD; + } + get_cpu_id(&cpu_id); add_device_randomness(&cpu_id, sizeof(cpu_id)); switch (cpu_id.machine) { -- cgit v1.2.3-59-g8ed1b From 57d7f939e7bdd746992f5c318a78697ba837c523 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 22 Mar 2016 10:54:24 +0100 Subject: s390: add no-execute support Bit 0x100 of a page table, segment table of region table entry can be used to disallow code execution for the virtual addresses associated with the entry. There is one tricky bit, the system call to return from a signal is part of the signal frame written to the user stack. With a non-executable stack this would stop working. To avoid breaking things the protection fault handler checks the opcode that caused the fault for 0x0a77 (sys_sigreturn) and 0x0aad (sys_rt_sigreturn) and injects a system call. This is preferable to the alternative solution with a stub function in the vdso because it works for vdso=off and statically linked binaries as well. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cacheflush.h | 30 ++++++++-- arch/s390/include/asm/pgtable.h | 95 +++++++++++++++++++----------- arch/s390/include/asm/setup.h | 2 + arch/s390/kernel/early.c | 19 ++++++ arch/s390/kernel/entry.S | 12 ++-- arch/s390/kernel/kprobes.c | 8 ++- arch/s390/kernel/module.c | 3 +- arch/s390/kernel/vmlinux.lds.S | 9 ++- arch/s390/mm/dump_pagetables.c | 15 +++-- arch/s390/mm/fault.c | 42 +++++++++++-- arch/s390/mm/hugetlbpage.c | 10 +++- arch/s390/mm/init.c | 3 + arch/s390/mm/pageattr.c | 117 +++++++++++++++++-------------------- arch/s390/mm/pgtable.c | 2 + arch/s390/mm/vmem.c | 42 +++++++++---- 15 files changed, 277 insertions(+), 132 deletions(-) diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h index 58fae7d098cf..0499334f9473 100644 --- a/arch/s390/include/asm/cacheflush.h +++ b/arch/s390/include/asm/cacheflush.h @@ -4,9 +4,31 @@ /* Caches aren't brain-dead on the s390. */ #include -int set_memory_ro(unsigned long addr, int numpages); -int set_memory_rw(unsigned long addr, int numpages); -int set_memory_nx(unsigned long addr, int numpages); -int set_memory_x(unsigned long addr, int numpages); +#define SET_MEMORY_RO 1UL +#define SET_MEMORY_RW 2UL +#define SET_MEMORY_NX 4UL +#define SET_MEMORY_X 8UL + +int __set_memory(unsigned long addr, int numpages, unsigned long flags); + +static inline int set_memory_ro(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_RO); +} + +static inline int set_memory_rw(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_RW); +} + +static inline int set_memory_nx(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_NX); +} + +static inline int set_memory_x(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_X); +} #endif /* _S390_CACHEFLUSH_H */ diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0362cd5fa187..d03b60d53f99 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -200,6 +200,7 @@ static inline int is_module_addr(void *addr) */ /* Hardware bits in the page table entry */ +#define _PAGE_NOEXEC 0x100 /* HW no-execute bit */ #define _PAGE_PROTECT 0x200 /* HW read-only bit */ #define _PAGE_INVALID 0x400 /* HW invalid bit */ #define _PAGE_LARGE 0x800 /* Bit to mark a large pte */ @@ -277,6 +278,7 @@ static inline int is_module_addr(void *addr) /* Bits in the region table entry */ #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ #define _REGION_ENTRY_PROTECT 0x200 /* region protection bit */ +#define _REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */ #define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */ #define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */ #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ @@ -316,6 +318,7 @@ static inline int is_module_addr(void *addr) #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ #define _SEGMENT_ENTRY_PROTECT 0x200 /* page protection bit */ +#define _SEGMENT_ENTRY_NOEXEC 0x100 /* region no-execute bit */ #define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */ #define _SEGMENT_ENTRY (0) @@ -385,17 +388,23 @@ static inline int is_module_addr(void *addr) * Page protection definitions. */ #define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_INVALID | _PAGE_PROTECT) -#define PAGE_READ __pgprot(_PAGE_PRESENT | _PAGE_READ | \ +#define PAGE_RO __pgprot(_PAGE_PRESENT | _PAGE_READ | \ + _PAGE_NOEXEC | _PAGE_INVALID | _PAGE_PROTECT) +#define PAGE_RX __pgprot(_PAGE_PRESENT | _PAGE_READ | \ _PAGE_INVALID | _PAGE_PROTECT) -#define PAGE_WRITE __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ +#define PAGE_RW __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_NOEXEC | _PAGE_INVALID | _PAGE_PROTECT) +#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ _PAGE_INVALID | _PAGE_PROTECT) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ - _PAGE_YOUNG | _PAGE_DIRTY) + _PAGE_YOUNG | _PAGE_DIRTY | _PAGE_NOEXEC) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ - _PAGE_YOUNG | _PAGE_DIRTY) + _PAGE_YOUNG | _PAGE_DIRTY | _PAGE_NOEXEC) #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_YOUNG | \ - _PAGE_PROTECT) + _PAGE_PROTECT | _PAGE_NOEXEC) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_YOUNG | _PAGE_DIRTY) /* * On s390 the page table entry has an invalid bit and a read-only bit. @@ -404,43 +413,51 @@ static inline int is_module_addr(void *addr) */ /*xwr*/ #define __P000 PAGE_NONE -#define __P001 PAGE_READ -#define __P010 PAGE_READ -#define __P011 PAGE_READ -#define __P100 PAGE_READ -#define __P101 PAGE_READ -#define __P110 PAGE_READ -#define __P111 PAGE_READ +#define __P001 PAGE_RO +#define __P010 PAGE_RO +#define __P011 PAGE_RO +#define __P100 PAGE_RX +#define __P101 PAGE_RX +#define __P110 PAGE_RX +#define __P111 PAGE_RX #define __S000 PAGE_NONE -#define __S001 PAGE_READ -#define __S010 PAGE_WRITE -#define __S011 PAGE_WRITE -#define __S100 PAGE_READ -#define __S101 PAGE_READ -#define __S110 PAGE_WRITE -#define __S111 PAGE_WRITE +#define __S001 PAGE_RO +#define __S010 PAGE_RW +#define __S011 PAGE_RW +#define __S100 PAGE_RX +#define __S101 PAGE_RX +#define __S110 PAGE_RWX +#define __S111 PAGE_RWX /* * Segment entry (large page) protection definitions. */ #define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \ _SEGMENT_ENTRY_PROTECT) -#define SEGMENT_READ __pgprot(_SEGMENT_ENTRY_PROTECT | \ +#define SEGMENT_RO __pgprot(_SEGMENT_ENTRY_PROTECT | \ + _SEGMENT_ENTRY_READ | \ + _SEGMENT_ENTRY_NOEXEC) +#define SEGMENT_RX __pgprot(_SEGMENT_ENTRY_PROTECT | \ _SEGMENT_ENTRY_READ) -#define SEGMENT_WRITE __pgprot(_SEGMENT_ENTRY_READ | \ +#define SEGMENT_RW __pgprot(_SEGMENT_ENTRY_READ | \ + _SEGMENT_ENTRY_WRITE | \ + _SEGMENT_ENTRY_NOEXEC) +#define SEGMENT_RWX __pgprot(_SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_WRITE) #define SEGMENT_KERNEL __pgprot(_SEGMENT_ENTRY | \ _SEGMENT_ENTRY_LARGE | \ _SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_WRITE | \ _SEGMENT_ENTRY_YOUNG | \ - _SEGMENT_ENTRY_DIRTY) + _SEGMENT_ENTRY_DIRTY | \ + _SEGMENT_ENTRY_NOEXEC) #define SEGMENT_KERNEL_RO __pgprot(_SEGMENT_ENTRY | \ _SEGMENT_ENTRY_LARGE | \ _SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_YOUNG | \ - _SEGMENT_ENTRY_PROTECT) + _SEGMENT_ENTRY_PROTECT | \ + _SEGMENT_ENTRY_NOEXEC) /* * Region3 entry (large page) protection definitions. @@ -451,12 +468,14 @@ static inline int is_module_addr(void *addr) _REGION3_ENTRY_READ | \ _REGION3_ENTRY_WRITE | \ _REGION3_ENTRY_YOUNG | \ - _REGION3_ENTRY_DIRTY) + _REGION3_ENTRY_DIRTY | \ + _REGION_ENTRY_NOEXEC) #define REGION3_KERNEL_RO __pgprot(_REGION_ENTRY_TYPE_R3 | \ _REGION3_ENTRY_LARGE | \ _REGION3_ENTRY_READ | \ _REGION3_ENTRY_YOUNG | \ - _REGION_ENTRY_PROTECT) + _REGION_ENTRY_PROTECT | \ + _REGION_ENTRY_NOEXEC) static inline int mm_has_pgste(struct mm_struct *mm) { @@ -801,14 +820,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) pte_val(pte) &= _PAGE_CHG_MASK; pte_val(pte) |= pgprot_val(newprot); /* - * newprot for PAGE_NONE, PAGE_READ and PAGE_WRITE has the - * invalid bit set, clear it again for readable, young pages + * newprot for PAGE_NONE, PAGE_RO, PAGE_RX, PAGE_RW and PAGE_RWX + * has the invalid bit set, clear it again for readable, young pages */ if ((pte_val(pte) & _PAGE_YOUNG) && (pte_val(pte) & _PAGE_READ)) pte_val(pte) &= ~_PAGE_INVALID; /* - * newprot for PAGE_READ and PAGE_WRITE has the page protection - * bit set, clear it again for writable, dirty pages + * newprot for PAGE_RO, PAGE_RX, PAGE_RW and PAGE_RWX has the page + * protection bit set, clear it again for writable, dirty pages */ if ((pte_val(pte) & _PAGE_DIRTY) && (pte_val(pte) & _PAGE_WRITE)) pte_val(pte) &= ~_PAGE_PROTECT; @@ -1029,6 +1048,8 @@ int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t entry) { + if (!MACHINE_HAS_NX) + pte_val(entry) &= ~_PAGE_NOEXEC; if (mm_has_pgste(mm)) ptep_set_pte_at(mm, addr, ptep, entry); else @@ -1173,14 +1194,18 @@ static inline pud_t pud_mkdirty(pud_t pud) static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot) { /* - * pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx) - * Convert to segment table entry format. + * pgprot is PAGE_NONE, PAGE_RO, PAGE_RX, PAGE_RW or PAGE_RWX + * (see __Pxxx / __Sxxx). Convert to segment table entry format. */ if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE)) return pgprot_val(SEGMENT_NONE); - if (pgprot_val(pgprot) == pgprot_val(PAGE_READ)) - return pgprot_val(SEGMENT_READ); - return pgprot_val(SEGMENT_WRITE); + if (pgprot_val(pgprot) == pgprot_val(PAGE_RO)) + return pgprot_val(SEGMENT_RO); + if (pgprot_val(pgprot) == pgprot_val(PAGE_RX)) + return pgprot_val(SEGMENT_RX); + if (pgprot_val(pgprot) == pgprot_val(PAGE_RW)) + return pgprot_val(SEGMENT_RW); + return pgprot_val(SEGMENT_RWX); } static inline pmd_t pmd_mkyoung(pmd_t pmd) @@ -1315,6 +1340,8 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t entry) { + if (!MACHINE_HAS_NX) + pmd_val(entry) &= ~_SEGMENT_ENTRY_NOEXEC; *pmdp = entry; } diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 5e8d57e1cc5e..040a4b49ab42 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -30,6 +30,7 @@ #define MACHINE_FLAG_TLB_LC _BITUL(12) #define MACHINE_FLAG_VX _BITUL(13) #define MACHINE_FLAG_CAD _BITUL(14) +#define MACHINE_FLAG_NX _BITUL(15) #define LPP_MAGIC _BITUL(31) #define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL) @@ -71,6 +72,7 @@ extern void detect_memory_memblock(void); #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) #define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) +#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX) /* * Console mode. Override with conmode= diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index d756315b7985..4e65c79cc5f2 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -354,6 +354,10 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_VX; __ctl_set_bit(0, 17); } + if (test_facility(130)) { + S390_lowcore.machine_flags |= MACHINE_FLAG_NX; + __ctl_set_bit(0, 20); + } } static inline void save_vector_registers(void) @@ -384,6 +388,21 @@ static int __init disable_vector_extension(char *str) } early_param("novx", disable_vector_extension); +static int __init noexec_setup(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (!rc && !enabled) { + /* Disable no-execute support */ + S390_lowcore.machine_flags &= ~MACHINE_FLAG_NX; + __ctl_clear_bit(0, 20); + } + return rc; +} +early_param("noexec", noexec_setup); + static int __init cad_setup(char *str) { int val; diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f687f168c94d..34ab7e8d6a76 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -380,13 +380,11 @@ ENTRY(system_call) brasl %r14,do_signal TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL jno .Lsysc_return +.Lsysc_do_syscall: + lghi %r13,__TASK_thread lmg %r2,%r7,__PT_R2(%r11) # load svc arguments - lghi %r8,0 # svc 0 returns -ENOSYS - llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number - cghi %r1,NR_syscalls - jnl .Lsysc_nr_ok # invalid svc number -> do svc 0 - slag %r8,%r1,2 - j .Lsysc_nr_ok # restart svc + lghi %r1,0 # svc 0 returns -ENOSYS + j .Lsysc_do_svc # # _TIF_NOTIFY_RESUME is set, call do_notify_resume @@ -528,6 +526,8 @@ ENTRY(pgm_check_handler) LOCKDEP_SYS_EXIT tm __PT_PSW+1(%r11),0x01 # returning to user ? jno .Lsysc_restore + TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL + jo .Lsysc_do_syscall j .Lsysc_tif # diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 84e0557b16fe..76f9eda1d7c0 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -45,11 +45,17 @@ DEFINE_INSN_CACHE_OPS(dmainsn); static void *alloc_dmainsn_page(void) { - return (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + void *page; + + page = (void *) __get_free_page(GFP_KERNEL | GFP_DMA); + if (page) + set_memory_x((unsigned long) page, 1); + return page; } static void free_dmainsn_page(void *page) { + set_memory_nx((unsigned long) page, 1); free_page((unsigned long)page); } diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index fbc07891f9e7..1a27f307a920 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -45,7 +45,8 @@ void *module_alloc(unsigned long size) if (PAGE_ALIGN(size) > MODULES_LEN) return NULL; return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, + GFP_KERNEL, PAGE_KERNEL_EXEC, + 0, NUMA_NO_NODE, __builtin_return_address(0)); } diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 3667d20e997f..5ccf95396251 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -44,6 +44,7 @@ SECTIONS *(.gnu.warning) } :text = 0x0700 + . = ALIGN(PAGE_SIZE); _etext = .; /* End of text section */ NOTES :text :note @@ -79,7 +80,13 @@ SECTIONS . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; - INIT_TEXT_SECTION(PAGE_SIZE) + . = ALIGN(PAGE_SIZE); + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + VMLINUX_SYMBOL(_sinittext) = . ; + INIT_TEXT + . = ALIGN(PAGE_SIZE); + VMLINUX_SYMBOL(_einittext) = . ; + } /* * .exit.text is discarded at runtime, not link time, diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c index 861880df12c7..5a46b1d7e578 100644 --- a/arch/s390/mm/dump_pagetables.c +++ b/arch/s390/mm/dump_pagetables.c @@ -49,8 +49,8 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level) seq_printf(m, "I\n"); return; } - seq_printf(m, "%s", pr & _PAGE_PROTECT ? "RO " : "RW "); - seq_putc(m, '\n'); + seq_puts(m, (pr & _PAGE_PROTECT) ? "RO " : "RW "); + seq_puts(m, (pr & _PAGE_NOEXEC) ? "NX\n" : "X\n"); } static void note_page(struct seq_file *m, struct pg_state *st, @@ -117,7 +117,8 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st, for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) { st->current_address = addr; pte = pte_offset_kernel(pmd, addr); - prot = pte_val(*pte) & (_PAGE_PROTECT | _PAGE_INVALID); + prot = pte_val(*pte) & + (_PAGE_PROTECT | _PAGE_INVALID | _PAGE_NOEXEC); note_page(m, st, prot, 4); addr += PAGE_SIZE; } @@ -135,7 +136,9 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pmd = pmd_offset(pud, addr); if (!pmd_none(*pmd)) { if (pmd_large(*pmd)) { - prot = pmd_val(*pmd) & _SEGMENT_ENTRY_PROTECT; + prot = pmd_val(*pmd) & + (_SEGMENT_ENTRY_PROTECT | + _SEGMENT_ENTRY_NOEXEC); note_page(m, st, prot, 3); } else walk_pte_level(m, st, pmd, addr); @@ -157,7 +160,9 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pud = pud_offset(pgd, addr); if (!pud_none(*pud)) if (pud_large(*pud)) { - prot = pud_val(*pud) & _REGION_ENTRY_PROTECT; + prot = pud_val(*pud) & + (_REGION_ENTRY_PROTECT | + _REGION_ENTRY_NOEXEC); note_page(m, st, prot, 2); } else walk_pmd_level(m, st, pud, addr); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index d1faae5cdd12..bb5560eb2435 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -311,12 +311,34 @@ static noinline void do_sigbus(struct pt_regs *regs) force_sig_info(SIGBUS, &si, tsk); } -static noinline void do_fault_error(struct pt_regs *regs, int fault) +static noinline int signal_return(struct pt_regs *regs) +{ + u16 instruction; + int rc; + + rc = __get_user(instruction, (u16 __user *) regs->psw.addr); + if (rc) + return rc; + if (instruction == 0x0a77) { + set_pt_regs_flag(regs, PIF_SYSCALL); + regs->int_code = 0x00040077; + return 0; + } else if (instruction == 0x0aad) { + set_pt_regs_flag(regs, PIF_SYSCALL); + regs->int_code = 0x000400ad; + return 0; + } + return -EACCES; +} + +static noinline void do_fault_error(struct pt_regs *regs, int access, int fault) { int si_code; switch (fault) { case VM_FAULT_BADACCESS: + if (access == VM_EXEC && signal_return(regs) == 0) + break; case VM_FAULT_BADMAP: /* Bad memory access. Check if it is kernel or user space. */ if (user_mode(regs)) { @@ -324,7 +346,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) si_code = (fault == VM_FAULT_BADMAP) ? SEGV_MAPERR : SEGV_ACCERR; do_sigsegv(regs, si_code); - return; + break; } case VM_FAULT_BADCONTEXT: case VM_FAULT_PFAULT: @@ -525,7 +547,7 @@ out: void do_protection_exception(struct pt_regs *regs) { unsigned long trans_exc_code; - int fault; + int access, fault; trans_exc_code = regs->int_parm_long; /* @@ -544,9 +566,17 @@ void do_protection_exception(struct pt_regs *regs) do_low_address(regs); return; } - fault = do_exception(regs, VM_WRITE); + if (unlikely(MACHINE_HAS_NX && (trans_exc_code & 0x80))) { + regs->int_parm_long = (trans_exc_code & ~PAGE_MASK) | + (regs->psw.addr & PAGE_MASK); + access = VM_EXEC; + fault = VM_FAULT_BADACCESS; + } else { + access = VM_WRITE; + fault = do_exception(regs, access); + } if (unlikely(fault)) - do_fault_error(regs, fault); + do_fault_error(regs, access, fault); } NOKPROBE_SYMBOL(do_protection_exception); @@ -557,7 +587,7 @@ void do_dat_exception(struct pt_regs *regs) access = VM_READ | VM_EXEC | VM_WRITE; fault = do_exception(regs, access); if (unlikely(fault)) - do_fault_error(regs, fault); + do_fault_error(regs, access, fault); } NOKPROBE_SYMBOL(do_dat_exception); diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 4a0c5bce3552..a03816227719 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -59,6 +59,8 @@ static inline unsigned long __pte_to_rste(pte_t pte) rste |= move_set_bit(pte_val(pte), _PAGE_SOFT_DIRTY, _SEGMENT_ENTRY_SOFT_DIRTY); #endif + rste |= move_set_bit(pte_val(pte), _PAGE_NOEXEC, + _SEGMENT_ENTRY_NOEXEC); } else rste = _SEGMENT_ENTRY_INVALID; return rste; @@ -113,6 +115,8 @@ static inline pte_t __rste_to_pte(unsigned long rste) pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY, _PAGE_DIRTY); #endif + pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_NOEXEC, + _PAGE_NOEXEC); } else pte_val(pte) = _PAGE_INVALID; return pte; @@ -121,7 +125,11 @@ static inline pte_t __rste_to_pte(unsigned long rste) void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { - unsigned long rste = __pte_to_rste(pte); + unsigned long rste; + + rste = __pte_to_rste(pte); + if (!MACHINE_HAS_NX) + rste &= ~_SEGMENT_ENTRY_NOEXEC; /* Set correct table type for 2G hugepages */ if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index b67454ad8408..ba0c8d18e10d 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -137,6 +137,9 @@ void __init mem_init(void) void free_initmem(void) { + __set_memory((unsigned long) _sinittext, + (_einittext - _sinittext) >> PAGE_SHIFT, + SET_MEMORY_RW | SET_MEMORY_NX); free_initmem_default(POISON_FREE_INITMEM); } diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 44f150312a16..a1543b74ee00 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -81,24 +81,24 @@ static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr, } } -struct cpa { - unsigned int set_ro : 1; - unsigned int clear_ro : 1; -}; - static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end, - struct cpa cpa) + unsigned long flags) { pte_t *ptep, new; ptep = pte_offset(pmdp, addr); do { - if (pte_none(*ptep)) + new = *ptep; + if (pte_none(new)) return -EINVAL; - if (cpa.set_ro) - new = pte_wrprotect(*ptep); - else if (cpa.clear_ro) - new = pte_mkwrite(pte_mkdirty(*ptep)); + if (flags & SET_MEMORY_RO) + new = pte_wrprotect(new); + else if (flags & SET_MEMORY_RW) + new = pte_mkwrite(pte_mkdirty(new)); + if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX) + pte_val(new) |= _PAGE_NOEXEC; + else if (flags & SET_MEMORY_X) + pte_val(new) &= ~_PAGE_NOEXEC; pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE); ptep++; addr += PAGE_SIZE; @@ -112,14 +112,17 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr) unsigned long pte_addr, prot; pte_t *pt_dir, *ptep; pmd_t new; - int i, ro; + int i, ro, nx; pt_dir = vmem_pte_alloc(); if (!pt_dir) return -ENOMEM; pte_addr = pmd_pfn(*pmdp) << PAGE_SHIFT; ro = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT); + nx = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_NOEXEC); prot = pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL); + if (!nx) + prot &= ~_PAGE_NOEXEC; ptep = pt_dir; for (i = 0; i < PTRS_PER_PTE; i++) { pte_val(*ptep) = pte_addr | prot; @@ -133,19 +136,24 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr) return 0; } -static void modify_pmd_page(pmd_t *pmdp, unsigned long addr, struct cpa cpa) +static void modify_pmd_page(pmd_t *pmdp, unsigned long addr, + unsigned long flags) { - pmd_t new; - - if (cpa.set_ro) - new = pmd_wrprotect(*pmdp); - else if (cpa.clear_ro) - new = pmd_mkwrite(pmd_mkdirty(*pmdp)); + pmd_t new = *pmdp; + + if (flags & SET_MEMORY_RO) + new = pmd_wrprotect(new); + else if (flags & SET_MEMORY_RW) + new = pmd_mkwrite(pmd_mkdirty(new)); + if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX) + pmd_val(new) |= _SEGMENT_ENTRY_NOEXEC; + else if (flags & SET_MEMORY_X) + pmd_val(new) &= ~_SEGMENT_ENTRY_NOEXEC; pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); } static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end, - struct cpa cpa) + unsigned long flags) { unsigned long next; pmd_t *pmdp; @@ -163,9 +171,9 @@ static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end, return rc; continue; } - modify_pmd_page(pmdp, addr, cpa); + modify_pmd_page(pmdp, addr, flags); } else { - rc = walk_pte_level(pmdp, addr, next, cpa); + rc = walk_pte_level(pmdp, addr, next, flags); if (rc) return rc; } @@ -181,14 +189,17 @@ static int split_pud_page(pud_t *pudp, unsigned long addr) unsigned long pmd_addr, prot; pmd_t *pm_dir, *pmdp; pud_t new; - int i, ro; + int i, ro, nx; pm_dir = vmem_pmd_alloc(); if (!pm_dir) return -ENOMEM; pmd_addr = pud_pfn(*pudp) << PAGE_SHIFT; ro = !!(pud_val(*pudp) & _REGION_ENTRY_PROTECT); + nx = !!(pud_val(*pudp) & _REGION_ENTRY_NOEXEC); prot = pgprot_val(ro ? SEGMENT_KERNEL_RO : SEGMENT_KERNEL); + if (!nx) + prot &= ~_SEGMENT_ENTRY_NOEXEC; pmdp = pm_dir; for (i = 0; i < PTRS_PER_PMD; i++) { pmd_val(*pmdp) = pmd_addr | prot; @@ -202,19 +213,24 @@ static int split_pud_page(pud_t *pudp, unsigned long addr) return 0; } -static void modify_pud_page(pud_t *pudp, unsigned long addr, struct cpa cpa) +static void modify_pud_page(pud_t *pudp, unsigned long addr, + unsigned long flags) { - pud_t new; - - if (cpa.set_ro) - new = pud_wrprotect(*pudp); - else if (cpa.clear_ro) - new = pud_mkwrite(pud_mkdirty(*pudp)); + pud_t new = *pudp; + + if (flags & SET_MEMORY_RO) + new = pud_wrprotect(new); + else if (flags & SET_MEMORY_RW) + new = pud_mkwrite(pud_mkdirty(new)); + if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX) + pud_val(new) |= _REGION_ENTRY_NOEXEC; + else if (flags & SET_MEMORY_X) + pud_val(new) &= ~_REGION_ENTRY_NOEXEC; pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); } static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, - struct cpa cpa) + unsigned long flags) { unsigned long next; pud_t *pudp; @@ -232,9 +248,9 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, break; continue; } - modify_pud_page(pudp, addr, cpa); + modify_pud_page(pudp, addr, flags); } else { - rc = walk_pmd_level(pudp, addr, next, cpa); + rc = walk_pmd_level(pudp, addr, next, flags); } pudp++; addr = next; @@ -246,7 +262,7 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, static DEFINE_MUTEX(cpa_mutex); static int change_page_attr(unsigned long addr, unsigned long end, - struct cpa cpa) + unsigned long flags) { unsigned long next; int rc = -EINVAL; @@ -262,7 +278,7 @@ static int change_page_attr(unsigned long addr, unsigned long end, if (pgd_none(*pgdp)) break; next = pgd_addr_end(addr, end); - rc = walk_pud_level(pgdp, addr, next, cpa); + rc = walk_pud_level(pgdp, addr, next, flags); if (rc) break; cond_resched(); @@ -271,35 +287,10 @@ static int change_page_attr(unsigned long addr, unsigned long end, return rc; } -int set_memory_ro(unsigned long addr, int numpages) +int __set_memory(unsigned long addr, int numpages, unsigned long flags) { - struct cpa cpa = { - .set_ro = 1, - }; - addr &= PAGE_MASK; - return change_page_attr(addr, addr + numpages * PAGE_SIZE, cpa); -} - -int set_memory_rw(unsigned long addr, int numpages) -{ - struct cpa cpa = { - .clear_ro = 1, - }; - - addr &= PAGE_MASK; - return change_page_attr(addr, addr + numpages * PAGE_SIZE, cpa); -} - -/* not possible */ -int set_memory_nx(unsigned long addr, int numpages) -{ - return 0; -} - -int set_memory_x(unsigned long addr, int numpages) -{ - return 0; + return change_page_attr(addr, addr + numpages * PAGE_SIZE, flags); } #ifdef CONFIG_DEBUG_PAGEALLOC @@ -339,7 +330,7 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) nr = min(numpages - i, nr); if (enable) { for (j = 0; j < nr; j++) { - pte_val(*pte) = address | pgprot_val(PAGE_KERNEL); + pte_val(*pte) &= ~_PAGE_INVALID; address += PAGE_SIZE; pte++; } diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 7a1897c51c54..190d0c65904a 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -274,6 +274,8 @@ void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, { pgste_t pgste; + if (!MACHINE_HAS_NX) + pte_val(pte) &= ~_PAGE_NOEXEC; if (mm_has_pgste(mm)) { pgste = pgste_get(ptep); pgste_set_key(ptep, pgste, pte, mm); diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 45becc8a44ec..253046344b3c 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -79,6 +79,7 @@ pte_t __ref *vmem_pte_alloc(void) */ static int vmem_add_mem(unsigned long start, unsigned long size) { + unsigned long pgt_prot, sgt_prot, r3_prot; unsigned long pages4k, pages1m, pages2g; unsigned long end = start + size; unsigned long address = start; @@ -88,6 +89,14 @@ static int vmem_add_mem(unsigned long start, unsigned long size) pte_t *pt_dir; int ret = -ENOMEM; + pgt_prot = pgprot_val(PAGE_KERNEL); + sgt_prot = pgprot_val(SEGMENT_KERNEL); + r3_prot = pgprot_val(REGION3_KERNEL); + if (!MACHINE_HAS_NX) { + pgt_prot &= ~_PAGE_NOEXEC; + sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC; + r3_prot &= ~_REGION_ENTRY_NOEXEC; + } pages4k = pages1m = pages2g = 0; while (address < end) { pg_dir = pgd_offset_k(address); @@ -101,7 +110,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address && !(address & ~PUD_MASK) && (address + PUD_SIZE <= end) && !debug_pagealloc_enabled()) { - pud_val(*pu_dir) = address | pgprot_val(REGION3_KERNEL); + pud_val(*pu_dir) = address | r3_prot; address += PUD_SIZE; pages2g++; continue; @@ -116,7 +125,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && !(address & ~PMD_MASK) && (address + PMD_SIZE <= end) && !debug_pagealloc_enabled()) { - pmd_val(*pm_dir) = address | pgprot_val(SEGMENT_KERNEL); + pmd_val(*pm_dir) = address | sgt_prot; address += PMD_SIZE; pages1m++; continue; @@ -129,7 +138,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) } pt_dir = pte_offset_kernel(pm_dir, address); - pte_val(*pt_dir) = address | pgprot_val(PAGE_KERNEL); + pte_val(*pt_dir) = address | pgt_prot; address += PAGE_SIZE; pages4k++; } @@ -200,6 +209,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) */ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) { + unsigned long pgt_prot, sgt_prot; unsigned long address = start; pgd_t *pg_dir; pud_t *pu_dir; @@ -207,6 +217,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) pte_t *pt_dir; int ret = -ENOMEM; + pgt_prot = pgprot_val(PAGE_KERNEL); + sgt_prot = pgprot_val(SEGMENT_KERNEL); + if (!MACHINE_HAS_NX) { + pgt_prot &= ~_PAGE_NOEXEC; + sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC; + } for (address = start; address < end;) { pg_dir = pgd_offset_k(address); if (pgd_none(*pg_dir)) { @@ -238,8 +254,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) new_page = vmemmap_alloc_block(PMD_SIZE, node); if (!new_page) goto out; - pmd_val(*pm_dir) = __pa(new_page) | - _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE; + pmd_val(*pm_dir) = __pa(new_page) | sgt_prot; address = (address + PMD_SIZE) & PMD_MASK; continue; } @@ -259,8 +274,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) new_page = vmemmap_alloc_block(PAGE_SIZE, node); if (!new_page) goto out; - pte_val(*pt_dir) = - __pa(new_page) | pgprot_val(PAGE_KERNEL); + pte_val(*pt_dir) = __pa(new_page) | pgt_prot; } address += PAGE_SIZE; } @@ -372,13 +386,21 @@ out: */ void __init vmem_map_init(void) { - unsigned long size = _eshared - _stext; struct memblock_region *reg; for_each_memblock(memory, reg) vmem_add_mem(reg->base, reg->size); - set_memory_ro((unsigned long)_stext, size >> PAGE_SHIFT); - pr_info("Write protected kernel read-only data: %luk\n", size >> 10); + __set_memory((unsigned long) _stext, + (_etext - _stext) >> PAGE_SHIFT, + SET_MEMORY_RO | SET_MEMORY_X); + __set_memory((unsigned long) _etext, + (_eshared - _etext) >> PAGE_SHIFT, + SET_MEMORY_RO); + __set_memory((unsigned long) _sinittext, + (_einittext - _sinittext) >> PAGE_SHIFT, + SET_MEMORY_RO | SET_MEMORY_X); + pr_info("Write protected kernel read-only data: %luk\n", + (_eshared - _stext) >> 10); } /* -- cgit v1.2.3-59-g8ed1b From a4a81d8eebdc1d209d034f62a082a5131e4242b5 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 7 Feb 2017 18:09:14 +0100 Subject: s390/kdump: Use "LINUX" ELF note name instead of "CORE" In binutils/libbfd (bfd/elf.c) it is enforced that all s390 specific ELF notes like e.g. NT_S390_PREFIX or NT_S390_CTRS have "LINUX" specified as note name. Otherwise the notes are ignored. For /proc/vmcore we currently use "CORE" for these notes. Up to now this has not been a real problem because the dump analysis tool "crash" does not check the note name. But it will break all programs that use libbfd for processing ELF notes. So fix this and use "LINUX" for all s390 specific notes to comply with libbfd. Cc: stable@vger.kernel.org # v4.4+ Reported-by: Philipp Rudo Reviewed-by: Philipp Rudo Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/crash_dump.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index f9293bfefb7f..408b4f4fda0f 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -329,7 +329,11 @@ static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len, static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len) { - return nt_init_name(buf, type, desc, d_len, KEXEC_CORE_NOTE_NAME); + const char *note_name = "LINUX"; + + if (type == NT_PRPSINFO || type == NT_PRSTATUS || type == NT_PRFPREG) + note_name = KEXEC_CORE_NOTE_NAME; + return nt_init_name(buf, type, desc, d_len, note_name); } /* -- cgit v1.2.3-59-g8ed1b From 3994a52b54569c4d71d43e3e00464eb9127f86a5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 9 Feb 2017 15:20:23 -0500 Subject: s390: kernel: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each change instance for the presence of either and replace as needed. Build testing revealed some implicit header usage that was fixed up accordingly. Signed-off-by: Paul Gortmaker Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/compat_linux.c | 1 - arch/s390/kernel/cpcmd.c | 2 +- arch/s390/kernel/crash_dump.c | 3 ++- arch/s390/kernel/debug.c | 2 +- arch/s390/kernel/diag.c | 3 ++- arch/s390/kernel/dis.c | 2 +- arch/s390/kernel/ebcdic.c | 4 ++-- arch/s390/kernel/ipl.c | 3 ++- arch/s390/kernel/irq.c | 3 ++- arch/s390/kernel/jump_label.c | 1 - arch/s390/kernel/nmi.c | 2 +- arch/s390/kernel/process.c | 2 +- arch/s390/kernel/smp.c | 2 +- arch/s390/kernel/stacktrace.c | 2 +- arch/s390/kernel/sysinfo.c | 2 +- arch/s390/kernel/time.c | 2 +- arch/s390/kernel/vdso.c | 2 +- 17 files changed, 20 insertions(+), 18 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 96df4547377a..a3d14161abcb 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 7f48e568ac64..9f0e4a2785f7 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -9,7 +9,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 408b4f4fda0f..e2293c662bdf 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 20a5a4286368..530226b6cb19 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index a97354c8c667..ac6abcd3fe6a 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -5,7 +5,8 @@ * Author(s): Michael Holzheu */ -#include +#include +#include #include #include #include diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 9f017cf417f6..f7e82302a71e 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index b971c6be6298..1d5392b36ad8 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -8,8 +8,8 @@ * Martin Peschke */ -#include -#include +#include +#include #include /* diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 5b91308f6117..b67dafb7b7cf 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -8,7 +8,8 @@ */ #include -#include +#include +#include #include #include #include diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index ef60f4177331..6dca93b29bed 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -12,11 +12,12 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c index 083b05f5f5ab..6aa630a8d24f 100644 --- a/arch/s390/kernel/jump_label.c +++ b/arch/s390/kernel/jump_label.c @@ -4,7 +4,6 @@ * Copyright IBM Corp. 2011 * Author(s): Jan Glauber */ -#include #include #include #include diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 9862196b4b89..56e14d073167 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 400d14f0b9f5..c5b86b4a1a8b 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e49f61aadaf9..d0a74d7ce433 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 355db9db8210..0085b2d8ed7d 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include static int __save_address(void *data, unsigned long address, int nosched) { diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index 24021c1e3ecb..12b6b138e354 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 546e513a0271..de66abb479c9 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 5904abf6b1ae..10516ae3b55e 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -9,7 +9,7 @@ * as published by the Free Software Foundation. */ -#include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From ff24b07abbe0a513ba4b5083c8aeaca6d548e364 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 9 Feb 2017 15:20:24 -0500 Subject: s390: mm: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each change instance for the presence of either and replace as needed. An instance where module_param was used without moduleparam.h was also fixed, as well as an implict use of asm/elf.h header. Signed-off-by: Paul Gortmaker Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/cmm.c | 1 + arch/s390/mm/dump_pagetables.c | 1 - arch/s390/mm/extmem.c | 2 +- arch/s390/mm/mem_detect.c | 1 - arch/s390/mm/mmap.c | 2 +- arch/s390/mm/pageattr.c | 1 - arch/s390/mm/vmem.c | 2 +- 7 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 79ddd580d605..829c63dbc81a 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c index 5a46b1d7e578..145a0ccb5845 100644 --- a/arch/s390/mm/dump_pagetables.c +++ b/arch/s390/mm/dump_pagetables.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 91af69f1dce5..9f118629b55f 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c index 185e70d3e153..e58dca05b962 100644 --- a/arch/s390/mm/mem_detect.c +++ b/arch/s390/mm/mem_detect.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index eb9df2822da1..7ae1282d5be9 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -26,11 +26,11 @@ #include #include #include -#include #include #include #include #include +#include static unsigned long stack_maxrandom_size(void) { diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index a1543b74ee00..fc5dc33bb141 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -3,7 +3,6 @@ * Author(s): Jan Glauber */ #include -#include #include #include #include diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 253046344b3c..60d38993f232 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From d321796753f5305a00a5f4996dbbb996994df45c Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 9 Feb 2017 15:20:25 -0500 Subject: s390: Audit and remove any remaining unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each change instance for the presence of either and replace as needed. An instance where module_param was used without moduleparam.h was also fixed, as well as implicit use of ptrace.h and string.h headers. Signed-off-by: Paul Gortmaker Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/livepatch.h | 2 +- arch/s390/kvm/kvm-s390.c | 1 + arch/s390/lib/delay.c | 2 +- arch/s390/lib/spinlock.c | 2 +- arch/s390/lib/string.c | 3 ++- arch/s390/lib/xor.c | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/livepatch.h b/arch/s390/include/asm/livepatch.h index 2c1213785892..6de5c6cb0061 100644 --- a/arch/s390/include/asm/livepatch.h +++ b/arch/s390/include/asm/livepatch.h @@ -17,7 +17,7 @@ #ifndef ASM_LIVEPATCH_H #define ASM_LIVEPATCH_H -#include +#include static inline int klp_check_compiler_support(void) { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index bec71e902be3..95562ee5cc44 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 501dcd4ca4a0..92e90e40b6fb 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index e48a48ec24bc..03462326ca3e 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index f71d9f655970..4ee27339c792 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -9,7 +9,8 @@ #define IN_ARCH_STRING_C 1 #include -#include +#include +#include /* * Helper functions to find the end of a string diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c index 7d94e3ec34a9..b4fd05c36151 100644 --- a/arch/s390/lib/xor.c +++ b/arch/s390/lib/xor.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include static void xor_xc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) -- cgit v1.2.3-59-g8ed1b From 187b5f41b4f15feae8b59e3a9ccaa7df85518bbb Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 10 Feb 2017 12:34:49 +0100 Subject: s390: replace ACCESS_ONCE with READ_ONCE Remove the last places of ACCESS_ONCE in s390 code. Signed-off-by: Christian Borntraeger Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/spinlock.h | 2 +- arch/s390/kernel/idle.c | 14 +++++++------- arch/s390/lib/spinlock.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 7ecd8902a5c3..ffc45048ea7d 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -63,7 +63,7 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock) static inline int arch_spin_is_locked(arch_spinlock_t *lp) { - return ACCESS_ONCE(lp->lock) != 0; + return READ_ONCE(lp->lock) != 0; } static inline int arch_spin_trylock_once(arch_spinlock_t *lp) diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c index 7a55c29b0b33..8e5ef334bee5 100644 --- a/arch/s390/kernel/idle.c +++ b/arch/s390/kernel/idle.c @@ -57,8 +57,8 @@ static ssize_t show_idle_count(struct device *dev, do { seq = read_seqcount_begin(&idle->seqcount); - idle_count = ACCESS_ONCE(idle->idle_count); - if (ACCESS_ONCE(idle->clock_idle_enter)) + idle_count = READ_ONCE(idle->idle_count); + if (READ_ONCE(idle->clock_idle_enter)) idle_count++; } while (read_seqcount_retry(&idle->seqcount, seq)); return sprintf(buf, "%llu\n", idle_count); @@ -75,9 +75,9 @@ static ssize_t show_idle_time(struct device *dev, do { now = get_tod_clock(); seq = read_seqcount_begin(&idle->seqcount); - idle_time = ACCESS_ONCE(idle->idle_time); - idle_enter = ACCESS_ONCE(idle->clock_idle_enter); - idle_exit = ACCESS_ONCE(idle->clock_idle_exit); + idle_time = READ_ONCE(idle->idle_time); + idle_enter = READ_ONCE(idle->clock_idle_enter); + idle_exit = READ_ONCE(idle->clock_idle_exit); } while (read_seqcount_retry(&idle->seqcount, seq)); idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; return sprintf(buf, "%llu\n", idle_time >> 12); @@ -93,8 +93,8 @@ cputime64_t arch_cpu_idle_time(int cpu) do { now = get_tod_clock(); seq = read_seqcount_begin(&idle->seqcount); - idle_enter = ACCESS_ONCE(idle->clock_idle_enter); - idle_exit = ACCESS_ONCE(idle->clock_idle_exit); + idle_enter = READ_ONCE(idle->clock_idle_enter); + idle_exit = READ_ONCE(idle->clock_idle_exit); } while (read_seqcount_retry(&idle->seqcount, seq)); return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0; } diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 03462326ca3e..ba427eb6f14c 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -133,7 +133,7 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp) int count; for (count = spin_retry; count > 0; count--) { - owner = ACCESS_ONCE(lp->lock); + owner = READ_ONCE(lp->lock); /* Try to get the lock if it is free. */ if (!owner) { if (_raw_compare_and_swap(&lp->lock, 0, cpu)) -- cgit v1.2.3-59-g8ed1b From 604ddad038bfa0ae6f447c2ff29fcd430cec8181 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Feb 2017 14:58:36 +0100 Subject: s390/mm: make memory_block_size_bytes available for !MEMORY_HOTPLUG Fix this compile error for !MEMORY_HOTPLUG && NUMA: arch/s390/built-in.o: In function `emu_setup_size_adjust': arch/s390/numa/mode_emu.c:477: undefined reference to `memory_block_size_bytes' Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/init.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index ba0c8d18e10d..ee5066718b21 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -151,6 +151,15 @@ void __init free_initrd_mem(unsigned long start, unsigned long end) } #endif +unsigned long memory_block_size_bytes(void) +{ + /* + * Make sure the memory block size is always greater + * or equal than the memory increment size. + */ + return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm); +} + #ifdef CONFIG_MEMORY_HOTPLUG int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { @@ -194,15 +203,6 @@ int arch_add_memory(int nid, u64 start, u64 size, bool for_device) return rc; } -unsigned long memory_block_size_bytes(void) -{ - /* - * Make sure the memory block size is always greater - * or equal than the memory increment size. - */ - return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm); -} - #ifdef CONFIG_MEMORY_HOTREMOVE int arch_remove_memory(u64 start, u64 size) { -- cgit v1.2.3-59-g8ed1b From 466178fc4e2937685edb7be005da4eb28bb81d72 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Feb 2017 15:11:15 +0100 Subject: s390: get rid of MACHINE_HAS_PFMF and MACHINE_HAS_HPAGE Both MACHINE_HAS_PFMF and MACHINE_HAS_HPAGE are just an alias for MACHINE_HAS_EDAT1. So simply use MACHINE_HAS_EDAT1 instead. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/hugetlb.h | 2 +- arch/s390/include/asm/pgtable.h | 2 +- arch/s390/include/asm/setup.h | 3 --- arch/s390/kernel/setup.c | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index 4c7fac75090e..cd546a245c68 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h @@ -14,7 +14,7 @@ #define is_hugepage_only_range(mm, addr, len) 0 #define hugetlb_free_pgd_range free_pgd_range -#define hugepages_supported() (MACHINE_HAS_HPAGE) +#define hugepages_supported() (MACHINE_HAS_EDAT1) void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index d03b60d53f99..52511866fb14 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -1416,7 +1416,7 @@ static inline int pmd_trans_huge(pmd_t pmd) #define has_transparent_hugepage has_transparent_hugepage static inline int has_transparent_hugepage(void) { - return MACHINE_HAS_HPAGE ? 1 : 0; + return MACHINE_HAS_EDAT1 ? 1 : 0; } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 040a4b49ab42..30bdb5a027f3 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -59,9 +59,6 @@ extern void detect_memory_memblock(void); #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) #define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP) -#define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1 -#define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1 - #define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE) #define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 8d59f20a658f..e4d811f17971 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -749,7 +749,7 @@ static int __init setup_hwcaps(void) /* * Huge page support HWCAP_S390_HPAGE is bit 7. */ - if (MACHINE_HAS_HPAGE) + if (MACHINE_HAS_EDAT1) elf_hwcap |= HWCAP_S390_HPAGE; /* -- cgit v1.2.3-59-g8ed1b From 549f2bf594782faa440055255831c9a51940a651 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Feb 2017 15:20:18 +0100 Subject: s390/mm: add cond_resched call to kernel page table dumper Walking kernel page tables within the kernel page table dumper may potentially take a lot of time. This may lead to soft lockup warning messages. To avoid this add a cond_resched call for each pgd_level iteration. This is the same as "x86/mm/ptdump: Fix soft lockup in page table walker" for x86. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/dump_pagetables.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c index 145a0ccb5845..1b553d847140 100644 --- a/arch/s390/mm/dump_pagetables.c +++ b/arch/s390/mm/dump_pagetables.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -187,6 +188,7 @@ static void walk_pgd_level(struct seq_file *m) else note_page(m, &st, _PAGE_INVALID, 1); addr += PGDIR_SIZE; + cond_resched(); } /* Flush out the last page */ st.current_address = max_addr; -- cgit v1.2.3-59-g8ed1b From 1228f7befbf3280906e75f532a1700c7d3138117 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 16 Feb 2017 10:41:52 +0100 Subject: s390: add missing "do {} while (0)" loop constructs to multiline macros Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ctl_reg.h | 8 ++++---- arch/s390/include/asm/processor.h | 4 ++-- arch/s390/include/asm/uaccess.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index cf4c9a106049..d0441ad2a990 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -9,7 +9,7 @@ #include -#define __ctl_load(array, low, high) { \ +#define __ctl_load(array, low, high) do { \ typedef struct { char _[sizeof(array)]; } addrtype; \ \ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ @@ -18,9 +18,9 @@ : \ : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \ : "memory"); \ -} +} while (0) -#define __ctl_store(array, low, high) { \ +#define __ctl_store(array, low, high) do { \ typedef struct { char _[sizeof(array)]; } addrtype; \ \ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ @@ -28,7 +28,7 @@ " stctg %1,%2,%0\n" \ : "=Q" (*(addrtype *)(&array)) \ : "i" (low), "i" (high)); \ -} +} while (0) static inline void __ctl_set_bit(unsigned int cr, unsigned int bit) { diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 6bca916a5ba0..2e21c645343c 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -358,12 +358,12 @@ extern void (*s390_base_ext_handler_fn)(void); extern int memcpy_real(void *, void *, size_t); extern void memcpy_absolute(void *, void *, size_t); -#define mem_assign_absolute(dest, val) { \ +#define mem_assign_absolute(dest, val) do { \ __typeof__(dest) __tmp = (val); \ \ BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \ memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ -} +} while (0) #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 3d1d0f7b7d28..b2988fc60f65 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -38,13 +38,13 @@ #define get_fs() (current->thread.mm_segment) #define set_fs(x) \ -{ \ +do { \ unsigned long __pto; \ current->thread.mm_segment = (x); \ __pto = current->thread.mm_segment.ar4 ? \ S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ __ctl_load(__pto, 7, 7); \ -} +} while (0) #define segment_eq(a,b) ((a).ar4 == (b).ar4) -- cgit v1.2.3-59-g8ed1b From 260021e21b8fcc375984ac7733f93509bf9ad100 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 17 Feb 2017 08:12:10 +0100 Subject: s390/zcrypt: Removed unneeded debug feature directory creation. The ap bus code and the zcrypt api had invocations to the debug feature debugfs_create_dir() call but never populated these directories in any way. Removed this unneeded code. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 3 --- drivers/s390/crypto/zcrypt_api.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5fa699192864..5a3a18f7b896 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -86,7 +86,6 @@ static bool initialised; /* * AP bus related debug feature things. */ -static struct dentry *ap_dbf_root; debug_info_t *ap_dbf_info; /* @@ -1148,7 +1147,6 @@ static struct reset_call ap_reset_call = { int __init ap_debug_init(void) { - ap_dbf_root = debugfs_create_dir("ap", NULL); ap_dbf_info = debug_register("ap", 1, 1, DBF_MAX_SPRINTF_ARGS * sizeof(long)); debug_register_view(ap_dbf_info, &debug_sprintf_view); @@ -1159,7 +1157,6 @@ int __init ap_debug_init(void) void ap_debug_exit(void) { - debugfs_remove(ap_dbf_root); debug_unregister(ap_dbf_info); } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 926169c3d9b9..144a17941e6f 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -81,7 +81,6 @@ EXPORT_SYMBOL(zcrypt_rescan_req); static LIST_HEAD(zcrypt_ops_list); /* Zcrypt related debug feature stuff. */ -static struct dentry *zcrypt_dbf_root; debug_info_t *zcrypt_dbf_info; /** @@ -1427,7 +1426,6 @@ void zcrypt_rng_device_remove(void) int __init zcrypt_debug_init(void) { - zcrypt_dbf_root = debugfs_create_dir("zcrypt", NULL); zcrypt_dbf_info = debug_register("zcrypt", 1, 1, DBF_MAX_SPRINTF_ARGS * sizeof(long)); debug_register_view(zcrypt_dbf_info, &debug_sprintf_view); @@ -1438,7 +1436,6 @@ int __init zcrypt_debug_init(void) void zcrypt_debug_exit(void) { - debugfs_remove(zcrypt_dbf_root); debug_unregister(zcrypt_dbf_info); } -- cgit v1.2.3-59-g8ed1b From 50a0d46c98b72cde3c6945f066c0adf31e4e8590 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 9 Feb 2017 09:48:10 -0500 Subject: s390/zcrypt: make ap_bus explicitly non-modular The Makefile in drivers/s390 has: obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/ and the Makefile in crypto/ has: ap-objs := ap_bus.o ap_card.o ap_queue.o meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. Also note that MODULE_ALIAS is a no-op for non-module builds. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. We replace module.h with moduleparam.h since the file does declare some module parameters even though it is not modular itself. Signed-off-by: Paul Gortmaker Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 54 +++----------------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5a3a18f7b896..56db76c05775 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -27,7 +27,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include +#include #include #include #include @@ -54,16 +54,7 @@ #include "ap_debug.h" /* - * Module description. - */ -MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \ - "Copyright IBM Corp. 2006, 2012"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CRYPTO("z90crypt"); - -/* - * Module parameter + * Module parameters; note though this file itself isn't modular. */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ static DEFINE_SPINLOCK(ap_domain_lock); @@ -1267,43 +1258,4 @@ out_free: kfree(ap_configuration); return rc; } - -/** - * ap_modules_exit(): The module termination code - * - * Terminates the module. - */ -void ap_module_exit(void) -{ - int i; - - initialised = false; - ap_reset_domain(); - ap_poll_thread_stop(); - del_timer_sync(&ap_config_timer); - hrtimer_cancel(&ap_poll_timer); - tasklet_kill(&ap_tasklet); - - /* first remove queue devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, - __ap_queue_devices_unregister); - /* now remove the card devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, - __ap_card_devices_unregister); - - /* remove bus attributes */ - for (i = 0; ap_bus_attrs[i]; i++) - bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); - unregister_pm_notifier(&ap_power_notifier); - root_device_unregister(ap_root_device); - bus_unregister(&ap_bus_type); - kfree(ap_configuration); - unregister_reset_call(&ap_reset_call); - if (ap_using_interrupts()) - unregister_adapter_interrupt(&ap_airq); - - ap_debug_exit(); -} - -module_init(ap_module_init); -module_exit(ap_module_exit); +device_initcall(ap_module_init); -- cgit v1.2.3-59-g8ed1b From d24b98e3a9c66b16ed029e1b2bcdf3c90e9d82d9 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 20 Feb 2017 09:51:36 +0100 Subject: s390/syscall: fix single stepped system calls Fix PER tracing of system calls after git commit 34525e1f7e8dc478 "s390: store breaking event address only for program checks" broke it. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/entry.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 34ab7e8d6a76..db469fa11462 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -545,6 +545,7 @@ ENTRY(pgm_check_handler) # .Lpgm_svcper: mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW + lghi %r13,__TASK_thread larl %r14,.Lsysc_per stg %r14,__LC_RETURN_PSW+8 lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP -- cgit v1.2.3-59-g8ed1b