From fd346c9dae6b266f8c3f62df20237059a3a90312 Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Fri, 20 May 2016 18:51:20 +0530 Subject: s390/keyboard: use memdup_user_nul() Use memdup_user_nul to duplicate a memory region from user-space to kernel-space and terminate with a NULL, instead of open coding using kmalloc + copy_from_user and explicitly NULL terminating. Signed-off-by: Muhammad Falak R Wani [heiko.carstens@de.ibm.com: remove comment] Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/keyboard.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index ef04a9f7a704..7b9c50aa4cc9 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -438,18 +438,9 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, return -EFAULT; if (len > sizeof(u_kbs->kb_string)) return -EINVAL; - p = kmalloc(len, GFP_KERNEL); - if (!p) - return -ENOMEM; - if (copy_from_user(p, u_kbs->kb_string, len)) { - kfree(p); - return -EFAULT; - } - /* - * Make sure the string is terminated by 0. User could have - * modified it between us running strnlen_user() and copying it. - */ - p[len - 1] = 0; + p = memdup_user_nul(u_kbs->kb_string, len); + if (IS_ERR(p)) + return PTR_ERR(p); kfree(kbd->func_table[kb_func]); kbd->func_table[kb_func] = p; break; -- cgit v1.2.3-58-ga151 From 097a116c7e9023267b61fb96b37fdcb2864a1ae3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 14 Apr 2016 12:35:22 +0200 Subject: s390/cpuinfo: show dynamic and static cpu mhz Show the dynamic and static cpu mhz of each cpu. Since these values are per cpu this requires a fundamental extension of the format of /proc/cpuinfo. Historically we had only a single line per cpu and a summary at the top of the file. This format is hardly extendible if we want to add more per cpu information. Therefore this patch adds per cpu blocks at the end of /proc/cpuinfo: cpu : 0 cpu Mhz dynamic : 5504 cpu Mhz static : 5504 cpu : 1 cpu Mhz dynamic : 5504 cpu Mhz static : 5504 cpu : 2 cpu Mhz dynamic : 5504 cpu Mhz static : 5504 cpu : 3 cpu Mhz dynamic : 5504 cpu Mhz static : 5504 Right now each block contains only the dynamic and static cpu mhz, but it can be easily extended like on every other architecture. This extension is supposed to be compatible with the old format. Signed-off-by: Heiko Carstens Acked-by: Sascha Silbe Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/processor.h | 17 +++++++++++- arch/s390/kernel/cache.c | 7 +---- arch/s390/kernel/processor.c | 55 +++++++++++++++++++++++++++++++++++---- arch/s390/kernel/setup.c | 1 + drivers/s390/char/sclp_config.c | 2 +- 5 files changed, 69 insertions(+), 13 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 9d4d311d7e52..09529202ea77 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -77,7 +77,10 @@ static inline void get_cpu_id(struct cpuid *ptr) asm volatile("stidp %0" : "=Q" (*ptr)); } -extern void s390_adjust_jiffies(void); +void s390_adjust_jiffies(void); +void s390_update_cpu_mhz(void); +void cpu_detect_mhz_feature(void); + extern const struct seq_operations cpuinfo_op; extern int sysctl_ieee_emulation_warnings; extern void execve_tail(void); @@ -233,6 +236,18 @@ void cpu_relax(void); #define cpu_relax_lowlatency() barrier() +#define ECAG_CACHE_ATTRIBUTE 0 +#define ECAG_CPU_ATTRIBUTE 1 + +static inline unsigned long __ecag(unsigned int asi, unsigned char parm) +{ + unsigned long val; + + asm volatile(".insn rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */ + : "=d" (val) : "a" (asi << 8 | parm)); + return val; +} + static inline void psw_set_key(unsigned int key) { asm volatile("spka 0(%0)" : : "d" (key)); diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c index 77a84bd78be2..c8a83276a4dc 100644 --- a/arch/s390/kernel/cache.c +++ b/arch/s390/kernel/cache.c @@ -99,12 +99,7 @@ static inline enum cache_type get_cache_type(struct cache_info *ci, int level) static inline unsigned long ecag(int ai, int li, int ti) { - unsigned long cmd, val; - - cmd = ai << 4 | li << 1 | ti; - asm volatile(".insn rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */ - : "=d" (val) : "a" (cmd)); - return val; + return __ecag(ECAG_CACHE_ATTRIBUTE, ai << 4 | li << 1 | ti); } static void ci_leaf_init(struct cacheinfo *this_leaf, int private, diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 4f7a96d719d0..06ca71b7ec0e 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -13,12 +13,45 @@ #include #include #include +#include #include #include #include #include -static DEFINE_PER_CPU(struct cpuid, cpu_id); +struct cpu_info { + unsigned int cpu_mhz_dynamic; + unsigned int cpu_mhz_static; + struct cpuid cpu_id; +}; + +static DEFINE_PER_CPU(struct cpu_info, cpu_info); + +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; +} + +static void update_cpu_mhz(void *arg) +{ + unsigned long mhz; + struct cpu_info *c; + + mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0); + c = this_cpu_ptr(&cpu_info); + c->cpu_mhz_dynamic = mhz >> 32; + c->cpu_mhz_static = mhz & 0xffffffff; +} + +void s390_update_cpu_mhz(void) +{ + s390_adjust_jiffies(); + if (machine_has_cpu_mhz) + on_each_cpu(update_cpu_mhz, NULL, 0); +} void notrace cpu_relax(void) { @@ -35,9 +68,11 @@ EXPORT_SYMBOL(cpu_relax); */ void cpu_init(void) { - struct cpuid *id = this_cpu_ptr(&cpu_id); + struct cpuid *id = this_cpu_ptr(&cpu_info.cpu_id); get_cpu_id(id); + if (machine_has_cpu_mhz) + update_cpu_mhz(NULL); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; BUG_ON(current->mm); @@ -64,7 +99,6 @@ static void show_cpu_summary(struct seq_file *m, void *v) }; int i, cpu; - s390_adjust_jiffies(); seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", @@ -80,7 +114,7 @@ static void show_cpu_summary(struct seq_file *m, void *v) seq_puts(m, "\n"); show_cacheinfo(m); for_each_online_cpu(cpu) { - struct cpuid *id = &per_cpu(cpu_id, cpu); + struct cpuid *id = &per_cpu(cpu_info.cpu_id, cpu); seq_printf(m, "processor %d: " "version = %02X, " @@ -90,6 +124,14 @@ static void show_cpu_summary(struct seq_file *m, void *v) } } +static void show_cpu_mhz(struct seq_file *m, unsigned long n) +{ + struct cpu_info *c = per_cpu_ptr(&cpu_info, n); + + seq_printf(m, "cpu MHz dynamic : %d\n", c->cpu_mhz_dynamic); + seq_printf(m, "cpu MHz static : %d\n", c->cpu_mhz_static); +} + /* * show_cpuinfo - Get information on one CPU for use by procfs. */ @@ -99,6 +141,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (!n) show_cpu_summary(m, v); + if (!machine_has_cpu_mhz) + return 0; + seq_printf(m, "\ncpu : %ld\n", n); + show_cpu_mhz(m, n); return 0; } @@ -132,4 +178,3 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; - diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f31939147ccd..d4e0742b197b 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -901,6 +901,7 @@ void __init setup_arch(char **cmdline_p) setup_vmcoreinfo(); setup_lowcore(); smp_fill_possible_mask(); + cpu_detect_mhz_feature(); cpu_init(); numa_setup(); diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 2ced50ccca63..1406fb688a26 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -47,7 +47,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) int cpu; struct device *dev; - s390_adjust_jiffies(); + s390_update_cpu_mhz(); pr_info("CPU capability may have changed\n"); get_online_cpus(); for_each_online_cpu(cpu) { -- cgit v1.2.3-58-ga151 From 99ec1112da4a0fc19103cb87df1cfa0e413fcbb3 Mon Sep 17 00:00:00 2001 From: Daniel van Gerpen Date: Mon, 23 May 2016 15:19:38 +0200 Subject: s390: use canonical include guard style Signed-off-by: Daniel van Gerpen Acked-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/fcx.h | 2 +- drivers/s390/cio/chp.h | 2 +- drivers/s390/cio/idset.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/fcx.h b/arch/s390/include/asm/fcx.h index 7ecb92b469b6..04cb4b4bcc5f 100644 --- a/arch/s390/include/asm/fcx.h +++ b/arch/s390/include/asm/fcx.h @@ -6,7 +6,7 @@ */ #ifndef _ASM_S390_FCX_H -#define _ASM_S390_FCX_H _ASM_S390_FCX_H +#define _ASM_S390_FCX_H #include diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index af0232290dc4..bb5a68226cda 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -4,7 +4,7 @@ */ #ifndef S390_CHP_H -#define S390_CHP_H S390_CHP_H +#define S390_CHP_H #include #include diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 22b58104683b..89a787790888 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -4,7 +4,7 @@ */ #ifndef S390_IDSET_H -#define S390_IDSET_H S390_IDSET_H +#define S390_IDSET_H #include -- cgit v1.2.3-58-ga151 From 2f82f57763d97700788cf228de1cf30ffd4153b4 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 31 May 2016 09:09:57 +0200 Subject: s390/time: STP sync clock correction The sync clock operation of the channel subsystem call for STP delivers the TOD clock difference as a result. Use this TOD clock difference instead of the difference between the TOD timestamps before and after the sync clock operation. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cio.h | 2 +- arch/s390/kernel/time.c | 11 +++++------ drivers/s390/cio/chsc.c | 8 ++++++-- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index d1e7b0a0feeb..f7ed88cc066e 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h @@ -320,7 +320,7 @@ struct cio_iplinfo { extern int cio_get_iplinfo(struct cio_iplinfo *iplinfo); /* Function from drivers/s390/cio/chsc.c */ -int chsc_sstpc(void *page, unsigned int op, u16 ctrl); +int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta); int chsc_sstpi(void *page, void *result, size_t size); #endif diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 9409d32f285e..a725fd1c4315 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -1455,7 +1455,7 @@ static void __init stp_reset(void) int rc; stp_page = (void *) get_zeroed_page(GFP_ATOMIC); - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); + rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000, NULL); if (rc == 0) set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); else if (stp_online) { @@ -1554,11 +1554,10 @@ static int stp_sync_clock(void *data) stp_info.todoff[2] || stp_info.todoff[3] || stp_info.tmd != 2) { old_clock = get_tod_clock(); - rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0); + rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta); if (rc == 0) { - new_clock = get_tod_clock(); + new_clock = old_clock + clock_delta; delta = adjust_time(old_clock, new_clock, 0); - clock_delta = new_clock - old_clock; atomic_notifier_call_chain(&s390_epoch_delta_notifier, 0, &clock_delta); fixup_clock_comparator(delta); @@ -1590,12 +1589,12 @@ static void stp_work_fn(struct work_struct *work) mutex_lock(&stp_work_mutex); if (!stp_online) { - chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); + chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000, NULL); del_timer_sync(&stp_timer); goto out_unlock; } - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); + rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0, NULL); if (rc) goto out_unlock; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c424c0c7367e..452193f7298c 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1176,7 +1176,7 @@ exit: EXPORT_SYMBOL_GPL(css_general_characteristics); EXPORT_SYMBOL_GPL(css_chsc_characteristics); -int chsc_sstpc(void *page, unsigned int op, u16 ctrl) +int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta) { struct { struct chsc_header request; @@ -1186,7 +1186,9 @@ int chsc_sstpc(void *page, unsigned int op, u16 ctrl) unsigned int ctrl : 16; unsigned int rsvd2[5]; struct chsc_header response; - unsigned int rsvd3[7]; + unsigned int rsvd3[3]; + u64 clock_delta; + unsigned int rsvd4[2]; } __attribute__ ((packed)) *rr; int rc; @@ -1200,6 +1202,8 @@ int chsc_sstpc(void *page, unsigned int op, u16 ctrl) if (rc) return -EIO; rc = (rr->response.code == 0x0001) ? 0 : -EIO; + if (clock_delta) + *clock_delta = rr->clock_delta; return rc; } -- cgit v1.2.3-58-ga151 From 4027789192d149678262ad606b2d7e2a61bed0f2 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 31 May 2016 10:16:24 +0200 Subject: s390/time: LPAR offset handling It is possible to specify a user offset for the TOD clock, e.g. +2 hours. The TOD clock will carry this offset even if the clock is synchronized with STP. This makes the time stamps acquired with get_sync_clock() useless as another LPAR migth use a different TOD offset. Use the PTFF instrution to get the TOD epoch difference and subtract it from the TOD clock value to get a physical timestamp. As the epoch difference contains the sync check delta as well the LPAR offset value to the physical clock needs to be refreshed after each clock synchronization. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/timex.h | 15 +++++++++++++- arch/s390/kernel/early.c | 1 + arch/s390/kernel/time.c | 46 ++++++++++++++++++++++++++++++++++-------- drivers/s390/block/dasd_eckd.c | 4 ++-- 4 files changed, 55 insertions(+), 11 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 920db0a2496b..0f34db4238da 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -52,6 +52,11 @@ static inline void store_clock_comparator(__u64 *time) void clock_comparator_work(void); +void __init ptff_init(void); + +extern unsigned char ptff_function_mask[16]; +extern unsigned long lpar_offset; + /* Function codes for the ptff instruction. */ #define PTFF_QAF 0x00 /* query available functions */ #define PTFF_QTO 0x01 /* query tod offset */ @@ -69,6 +74,14 @@ struct ptff_qto { unsigned long long tod_epoch_difference; } __packed; +static inline int ptff_query(unsigned int nr) +{ + unsigned char *ptr; + + ptr = ptff_function_mask + (nr >> 3); + return (*ptr & (0x80 >> (nr & 7))) != 0; +} + static inline int ptff(void *ptff_block, size_t len, unsigned int func) { typedef struct { char _[len]; } addrtype; @@ -138,7 +151,7 @@ static inline cycles_t get_cycles(void) return (cycles_t) get_tod_clock() >> 2; } -int get_sync_clock(unsigned long long *clock); +int get_phys_clock(unsigned long long *clock); void init_cpu_timer(void); unsigned long long monotonic_clock(void); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 4067dbe390ac..717b03aa16b5 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -467,6 +467,7 @@ void __init startup_init(void) ipl_save_parameters(); rescue_initrd(); clear_bss_section(); + ptff_init(); init_kernel_storage_key(); lockdep_off(); setup_lowcore_early(); diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index a725fd1c4315..d71623639997 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,25 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier); EXPORT_SYMBOL(s390_epoch_delta_notifier); +unsigned char ptff_function_mask[16]; +unsigned long lpar_offset; + +/* + * Get time offsets with PTFF + */ +void __init ptff_init(void) +{ + struct ptff_qto qto; + + if (!test_facility(28)) + return; + ptff(&ptff_function_mask, sizeof(ptff_function_mask), PTFF_QAF); + + /* get LPAR offset */ + if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0) + lpar_offset = qto.tod_epoch_difference; +} + /* * Scheduler clock - returns current time in nanosec units. */ @@ -337,20 +357,20 @@ static unsigned long clock_sync_flags; #define CLOCK_SYNC_STP 3 /* - * The synchronous get_clock function. It will write the current clock - * value to the clock pointer and return 0 if the clock is in sync with - * the external time source. If the clock mode is local it will return - * -EOPNOTSUPP and -EAGAIN if the clock is not in sync with the external - * reference. + * The get_clock function for the physical clock. It will get the current + * TOD clock, subtract the LPAR offset and write the result to *clock. + * The function returns 0 if the clock is in sync with the external time + * source. If the clock mode is local it will return -EOPNOTSUPP and + * -EAGAIN if the clock is not in sync with the external reference. */ -int get_sync_clock(unsigned long long *clock) +int get_phys_clock(unsigned long long *clock) { atomic_t *sw_ptr; unsigned int sw0, sw1; sw_ptr = &get_cpu_var(clock_sync_word); sw0 = atomic_read(sw_ptr); - *clock = get_tod_clock(); + *clock = get_tod_clock() - lpar_offset; sw1 = atomic_read(sw_ptr); put_cpu_var(clock_sync_word); if (sw0 == sw1 && (sw0 & 0x80000000U)) @@ -364,7 +384,7 @@ int get_sync_clock(unsigned long long *clock) return -EACCES; return -EAGAIN; } -EXPORT_SYMBOL(get_sync_clock); +EXPORT_SYMBOL(get_phys_clock); /* * Make get_sync_clock return -EAGAIN. @@ -758,6 +778,7 @@ static int etr_sync_clock(void *data) unsigned long long clock, old_clock, clock_delta, delay, delta; struct clock_sync_data *etr_sync; struct etr_aib *sync_port, *aib; + struct ptff_qto qto; int port; int rc; @@ -804,6 +825,10 @@ static int etr_sync_clock(void *data) etr_sync->in_sync = -EAGAIN; rc = -EAGAIN; } else { + if (ptff_query(PTFF_QTO) && + ptff(&qto, sizeof(qto), PTFF_QTO) == 0) + /* Update LPAR offset */ + lpar_offset = qto.tod_epoch_difference; etr_sync->in_sync = 1; rc = 0; } @@ -1533,6 +1558,7 @@ static int stp_sync_clock(void *data) static int first; unsigned long long old_clock, delta, new_clock, clock_delta; struct clock_sync_data *stp_sync; + struct ptff_qto qto; int rc; stp_sync = data; @@ -1558,6 +1584,10 @@ static int stp_sync_clock(void *data) if (rc == 0) { new_clock = old_clock + clock_delta; delta = adjust_time(old_clock, new_clock, 0); + if (ptff_query(PTFF_QTO) && + ptff(&qto, sizeof(qto), PTFF_QTO) == 0) + /* Update LPAR offset */ + lpar_offset = qto.tod_epoch_difference; atomic_notifier_call_chain(&s390_epoch_delta_notifier, 0, &clock_delta); fixup_clock_comparator(delta); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 42b34cd1f002..fd2eff440098 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -228,7 +228,7 @@ check_XRC (struct ccw1 *de_ccw, data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - rc = get_sync_clock(&data->ep_sys_time); + rc = get_phys_clock(&data->ep_sys_time); /* Ignore return code if sync clock is switched off. */ if (rc == -EOPNOTSUPP || rc == -EACCES) rc = 0; @@ -339,7 +339,7 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */ pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ - rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); + rc = get_phys_clock(&pfxdata->define_extent.ep_sys_time); /* Ignore return code if sync clock is switched off. */ if (rc == -EOPNOTSUPP || rc == -EACCES) rc = 0; -- cgit v1.2.3-58-ga151 From 0599eead5833d9dd0970b59fed3844441b44fe0c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 11 Jun 2016 11:24:27 +0200 Subject: s390/ipl: rename diagnose enums Rename DIAG308_IPL and DIAG308_DUMP to DIAG308_LOAD_CLEAR and DIAG308_LOAD_NORMAL_DUMP to better reflect the associated IPL functions. Suggested-by: Cornelia Huck Suggested-by: Christian Borntraeger Signed-off-by: Heiko Carstens Acked-by: Michael Holzheu Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ipl.h | 10 +++++----- arch/s390/kernel/ipl.c | 16 ++++++++-------- drivers/s390/char/zcore.c | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 6fc44dca193e..4da22b2f0521 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h @@ -141,11 +141,11 @@ extern void setup_ipl(void); * DIAG 308 support */ enum diag308_subcode { - DIAG308_REL_HSA = 2, - DIAG308_IPL = 3, - DIAG308_DUMP = 4, - DIAG308_SET = 5, - DIAG308_STORE = 6, + DIAG308_REL_HSA = 2, + DIAG308_LOAD_CLEAR = 3, + DIAG308_LOAD_NORMAL_DUMP = 4, + DIAG308_SET = 5, + DIAG308_STORE = 6, }; enum diag308_ipl_type { diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index b0dbf9a265f5..b892480cd4d8 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -563,7 +563,7 @@ static struct kset *ipl_kset; static void __ipl_run(void *unused) { - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); if (MACHINE_IS_VM) __cpcmd("IPL", NULL, 0, NULL); else if (ipl_info.type == IPL_TYPE_CCW) @@ -1086,23 +1086,23 @@ static void __reipl_run(void *unused) case REIPL_METHOD_CCW_DIAG: diag308(DIAG308_SET, reipl_block_ccw); if (MACHINE_IS_LPAR) - diag308(DIAG308_DUMP, NULL); + diag308(DIAG308_LOAD_NORMAL_DUMP, NULL); else - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); break; case REIPL_METHOD_FCP_RW_DIAG: diag308(DIAG308_SET, reipl_block_fcp); - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); break; case REIPL_METHOD_FCP_RO_DIAG: - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); break; case REIPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; case REIPL_METHOD_NSS_DIAG: diag308(DIAG308_SET, reipl_block_nss); - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); break; case REIPL_METHOD_NSS: get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS); @@ -1111,7 +1111,7 @@ static void __reipl_run(void *unused) case REIPL_METHOD_DEFAULT: if (MACHINE_IS_VM) __cpcmd("IPL", NULL, 0, NULL); - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); break; case REIPL_METHOD_FCP_DUMP: break; @@ -1426,7 +1426,7 @@ static void diag308_dump(void *dump_block) { diag308(DIAG308_SET, dump_block); while (1) { - if (diag308(DIAG308_DUMP, NULL) != 0x302) + if (diag308(DIAG308_LOAD_NORMAL_DUMP, NULL) != 0x302) break; udelay_simple(USEC_PER_SEC); } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 5043ecfa1fbc..16992e2a40ad 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -185,7 +185,7 @@ static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, { if (ipl_block) { diag308(DIAG308_SET, ipl_block); - diag308(DIAG308_IPL, NULL); + diag308(DIAG308_LOAD_CLEAR, NULL); } return count; } -- cgit v1.2.3-58-ga151 From 11d376730384a07568b56ca8d43989d25e585760 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 20 Jun 2016 14:00:27 +0200 Subject: s390/crypto: use basic blocks for ap bus inline assemblies Use only simple inline assemblies which consist of a single basic block if the register asm construct is being used. Otherwise gcc would generate broken code if the compiler option --sanitize-coverage=trace-pc would be used. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 77 ++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 28 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 327255da115a..4feb27215ab6 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -169,6 +169,19 @@ static int ap_configuration_available(void) return test_facility(12); } +static inline struct ap_queue_status +__pqap_tapq(ap_qid_t qid, unsigned long *info) +{ + register unsigned long reg0 asm ("0") = qid; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + *info = reg2; + return reg1; +} + /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number @@ -179,17 +192,15 @@ static int ap_configuration_available(void) static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, unsigned long *info) { - register unsigned long reg0 asm ("0") = qid; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = 0UL; + struct ap_queue_status aqs; + unsigned long _info; if (test_facility(15)) - reg0 |= 1UL << 23; /* set APFT T bit*/ - asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ - : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + qid |= 1UL << 23; /* set APFT T bit*/ + aqs = __pqap_tapq(qid, &_info); if (info) - *info = reg2; - return reg1; + *info = _info; + return aqs; } /** @@ -237,14 +248,12 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) * * Returns 0 on success, or -EOPNOTSUPP. */ -static inline int ap_query_configuration(void) +static inline int __ap_query_configuration(void) { register unsigned long reg0 asm ("0") = 0x04000000UL; register unsigned long reg1 asm ("1") = -EINVAL; register void *reg2 asm ("2") = (void *) ap_configuration; - if (!ap_configuration) - return -EOPNOTSUPP; asm volatile( ".long 0xb2af0000\n" /* PQAP(QCI) */ "0: la %1,0\n" @@ -257,6 +266,13 @@ static inline int ap_query_configuration(void) return reg1; } +static inline int ap_query_configuration(void) +{ + if (!ap_configuration) + return -EOPNOTSUPP; + return __ap_query_configuration(); +} + /** * ap_init_configuration(): Allocate and query configuration array. */ @@ -346,6 +362,26 @@ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) } } +static inline struct ap_queue_status +__nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) +{ + typedef struct { char _[length]; } msgblock; + 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; + register unsigned long reg3 asm ("3") = (unsigned long) length; + register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); + register unsigned long reg5 asm ("5") = psmid & 0xffffffff; + + asm volatile ( + "0: .long 0xb2ad0042\n" /* NQAP */ + " brc 2,0b" + : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) + : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg) + : "cc"); + return reg1; +} + /** * __ap_send(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -363,24 +399,9 @@ static inline struct ap_queue_status __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, unsigned int special) { - typedef struct { char _[length]; } msgblock; - 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; - register unsigned long reg3 asm ("3") = (unsigned long) length; - register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); - register unsigned long reg5 asm ("5") = psmid & 0xffffffff; - if (special == 1) - reg0 |= 0x400000UL; - - asm volatile ( - "0: .long 0xb2ad0042\n" /* NQAP */ - " brc 2,0b" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) - : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg) - : "cc" ); - return reg1; + qid |= 0x400000UL; + return __nqap(qid, psmid, msg, length); } int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) -- cgit v1.2.3-58-ga151 From 7b4ff87cbf3d2530d6362bb08cc61635894f596c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 20 Jun 2016 14:03:38 +0200 Subject: s390/cio: use basic blocks for cmf inline assemblies Use only simple inline assemblies which consist of a single basic block if the register asm construct is being used. Otherwise gcc would generate broken code if the compiler option --sanitize-coverage=trace-pc would be used. Signed-off-by: Heiko Carstens Acked-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cmf.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index b2afad5a5682..f18c83bacb09 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -164,6 +164,9 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } +#define CMF_OFF 0 +#define CMF_ON 2 + /* * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to @@ -176,7 +179,7 @@ static inline void cmf_activate(void *area, unsigned int onoff) register long __gpr1 asm("1"); __gpr2 = area; - __gpr1 = onoff ? 2 : 0; + __gpr1 = onoff; /* activate channel measurement */ asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } @@ -587,7 +590,7 @@ static int alloc_cmb(struct ccw_device *cdev) /* everything ok */ memset(mem, 0, size); cmb_area.mem = mem; - cmf_activate(cmb_area.mem, 1); + cmf_activate(cmb_area.mem, CMF_ON); } } @@ -621,7 +624,7 @@ static void free_cmb(struct ccw_device *cdev) if (list_empty(&cmb_area.list)) { ssize_t size; size = sizeof(struct cmb) * cmb_area.num_channels; - cmf_activate(NULL, 0); + cmf_activate(NULL, CMF_OFF); free_pages((unsigned long)cmb_area.mem, get_order(size)); cmb_area.mem = NULL; } @@ -830,7 +833,7 @@ static int alloc_cmbe(struct ccw_device *cdev) /* activate global measurement if this is the first channel */ if (list_empty(&cmb_area.list)) - cmf_activate(NULL, 1); + cmf_activate(NULL, CMF_ON); list_add_tail(&cdev->private->cmb_list, &cmb_area.list); spin_unlock_irq(cdev->ccwlock); @@ -867,7 +870,7 @@ static void free_cmbe(struct ccw_device *cdev) /* deactivate global measurement if this is the last channel */ list_del_init(&cdev->private->cmb_list); if (list_empty(&cmb_area.list)) - cmf_activate(NULL, 0); + cmf_activate(NULL, CMF_OFF); spin_unlock_irq(cdev->ccwlock); spin_unlock(&cmb_area.lock); } @@ -1321,7 +1324,7 @@ void cmf_reactivate(void) { spin_lock(&cmb_area.lock); if (!list_empty(&cmb_area.list)) - cmf_activate(cmb_area.mem, 1); + cmf_activate(cmb_area.mem, CMF_ON); spin_unlock(&cmb_area.lock); } -- cgit v1.2.3-58-ga151 From a4d9b97cc3c215a2dd6e841ee203db7b7e73b3c9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 20 Jun 2016 14:03:52 +0200 Subject: s390/cio: use basic blocks for i/o inline assemblies Use only simple inline assemblies which consist of a single basic block if the register asm construct is being used. Otherwise gcc would generate broken code if the compiler option --sanitize-coverage=trace-pc would be used. Signed-off-by: Heiko Carstens Acked-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ioasm.c | 91 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index 98984818618f..8225da619014 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -12,7 +12,7 @@ #include "orb.h" #include "cio.h" -int stsch(struct subchannel_id schid, struct schib *addr) +static inline int __stsch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; @@ -26,13 +26,21 @@ int stsch(struct subchannel_id schid, struct schib *addr) : "+d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); + return ccode; +} + +int stsch(struct subchannel_id schid, struct schib *addr) +{ + int ccode; + + ccode = __stsch(schid, addr); trace_s390_cio_stsch(schid, addr, ccode); return ccode; } EXPORT_SYMBOL(stsch); -int msch(struct subchannel_id schid, struct schib *addr) +static inline int __msch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; @@ -46,12 +54,20 @@ int msch(struct subchannel_id schid, struct schib *addr) : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + return ccode; +} + +int msch(struct subchannel_id schid, struct schib *addr) +{ + int ccode; + + ccode = __msch(schid, addr); trace_s390_cio_msch(schid, addr, ccode); return ccode; } -int tsch(struct subchannel_id schid, struct irb *addr) +static inline int __tsch(struct subchannel_id schid, struct irb *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; @@ -63,12 +79,20 @@ int tsch(struct subchannel_id schid, struct irb *addr) : "=d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); + return ccode; +} + +int tsch(struct subchannel_id schid, struct irb *addr) +{ + int ccode; + + ccode = __tsch(schid, addr); trace_s390_cio_tsch(schid, addr, ccode); return ccode; } -int ssch(struct subchannel_id schid, union orb *addr) +static inline int __ssch(struct subchannel_id schid, union orb *addr) { register struct subchannel_id reg1 asm("1") = schid; int ccode = -EIO; @@ -82,13 +106,21 @@ int ssch(struct subchannel_id schid, union orb *addr) : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc", "memory"); + return ccode; +} + +int ssch(struct subchannel_id schid, union orb *addr) +{ + int ccode; + + ccode = __ssch(schid, addr); trace_s390_cio_ssch(schid, addr, ccode); return ccode; } EXPORT_SYMBOL(ssch); -int csch(struct subchannel_id schid) +static inline int __csch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -100,6 +132,14 @@ int csch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int csch(struct subchannel_id schid) +{ + int ccode; + + ccode = __csch(schid); trace_s390_cio_csch(schid, ccode); return ccode; @@ -140,7 +180,7 @@ int chsc(void *chsc_area) } EXPORT_SYMBOL(chsc); -int rchp(struct chp_id chpid) +static inline int __rchp(struct chp_id chpid) { register struct chp_id reg1 asm ("1") = chpid; int ccode; @@ -151,12 +191,20 @@ int rchp(struct chp_id chpid) " ipm %0\n" " srl %0,28" : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int rchp(struct chp_id chpid) +{ + int ccode; + + ccode = __rchp(chpid); trace_s390_cio_rchp(chpid, ccode); return ccode; } -int rsch(struct subchannel_id schid) +static inline int __rsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -168,12 +216,21 @@ int rsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc", "memory"); + + return ccode; +} + +int rsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __rsch(schid); trace_s390_cio_rsch(schid, ccode); return ccode; } -int hsch(struct subchannel_id schid) +static inline int __hsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -185,12 +242,20 @@ int hsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int hsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __hsch(schid); trace_s390_cio_hsch(schid, ccode); return ccode; } -int xsch(struct subchannel_id schid) +static inline int __xsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -202,6 +267,14 @@ int xsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int xsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __xsch(schid); trace_s390_cio_xsch(schid, ccode); return ccode; -- cgit v1.2.3-58-ga151 From 8f50af49f564d4e57c03903ca374109bdc270ea9 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 7 Jul 2016 07:52:38 +0200 Subject: s390/console: Make preferred console handling more consistent Use the same code structure when determining preferred consoles for Linux running as KVM guest as with Linux running in LPAR and z/VM guest: - Extend the console_mode variable to cover vt220 and hvc consoles - Determine sensible console defaults in conmode_default() - Remove KVM-special handling in set_preferred_console() Ensure that the sclp line mode console is also registered when the vt220 console was selected to not change existing behavior that someone might be relying on. As an externally visible change, KVM guest users can now select the 3270 or 3215 console devices using the conmode= kernel parameter, provided that support for the corresponding driver was compiled into the kernel. Signed-off-by: Peter Oberparleiter Signed-off-by: Jing Liu Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/setup.h | 4 ++++ arch/s390/kernel/setup.c | 22 ++++++++++++++-------- drivers/s390/char/sclp_con.c | 3 ++- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index c0f0efbb6ab5..5e8d57e1cc5e 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -86,9 +86,13 @@ extern char vmpoff_cmd[]; #define CONSOLE_IS_SCLP (console_mode == 1) #define CONSOLE_IS_3215 (console_mode == 2) #define CONSOLE_IS_3270 (console_mode == 3) +#define CONSOLE_IS_VT220 (console_mode == 4) +#define CONSOLE_IS_HVC (console_mode == 5) #define SET_CONSOLE_SCLP do { console_mode = 1; } while (0) #define SET_CONSOLE_3215 do { console_mode = 2; } while (0) #define SET_CONSOLE_3270 do { console_mode = 3; } while (0) +#define SET_CONSOLE_VT220 do { console_mode = 4; } while (0) +#define SET_CONSOLE_HVC do { console_mode = 5; } while (0) #define NSS_NAME_SIZE 8 extern char kernel_nss_name[]; diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 00e38f0c75df..ba5f456edaa9 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -130,17 +130,14 @@ __setup("condev=", condev_setup); static void __init set_preferred_console(void) { - if (MACHINE_IS_KVM) { - if (sclp.has_vt220) - add_preferred_console("ttyS", 1, NULL); - else if (sclp.has_linemode) - add_preferred_console("ttyS", 0, NULL); - else - add_preferred_console("hvc", 0, NULL); - } else if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP) + if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP) add_preferred_console("ttyS", 0, NULL); else if (CONSOLE_IS_3270) add_preferred_console("tty3270", 0, NULL); + else if (CONSOLE_IS_VT220) + add_preferred_console("ttyS", 1, NULL); + else if (CONSOLE_IS_HVC) + add_preferred_console("hvc", 0, NULL); } static int __init conmode_setup(char *str) @@ -206,6 +203,15 @@ static void __init conmode_default(void) SET_CONSOLE_SCLP; #endif } + } else if (MACHINE_IS_KVM) { + if (sclp.has_vt220 && + config_enabled(CONFIG_SCLP_VT220_CONSOLE)) + SET_CONSOLE_VT220; + else if (sclp.has_linemode && + config_enabled(CONFIG_SCLP_CONSOLE)) + SET_CONSOLE_SCLP; + else + SET_CONSOLE_HVC; } else { #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 5880def98fc1..6037bc87e767 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -319,7 +319,8 @@ sclp_console_init(void) int i; int rc; - if (!CONSOLE_IS_SCLP) + /* SCLP consoles are handled together */ + if (!(CONSOLE_IS_SCLP || CONSOLE_IS_VT220)) return 0; rc = sclp_rw_init(); if (rc) -- cgit v1.2.3-58-ga151 From 0f5d050ceaa31b2229102211d60c149f920df3aa Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 12 Jul 2016 19:57:57 +0200 Subject: s390/cio: allow to reset channel measurement block Prior to commit 1bc6664bdfb949bc69a08113801e7d6acbf6bc3f a call to enable_cmf for a device for which channel measurement was already enabled resulted in a reset of the measurement data. What looked like bugs at the time (a 2nd allocation was triggered but failed, reset was called regardless of previous failures, and errors have not been reported to userspace) was actually something at least one userspace tool depended on. Restore that behavior in a sane way. Fixes: 1bc6664bdfb ("s390/cio: use device_lock during cmb activation") Cc: stable@vger.kernel.org #v4.4+ Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cmf.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index f18c83bacb09..268aa23afa01 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -756,6 +756,17 @@ static void reset_cmb(struct ccw_device *cdev) cmf_generic_reset(cdev); } +static int cmf_enabled(struct ccw_device *cdev) +{ + int enabled; + + spin_lock_irq(cdev->ccwlock); + enabled = !!cdev->private->cmb; + spin_unlock_irq(cdev->ccwlock); + + return enabled; +} + static struct attribute_group cmf_attr_group; static struct cmb_operations cmbops_basic = { @@ -1156,13 +1167,8 @@ static ssize_t cmb_enable_show(struct device *dev, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); - int enabled; - spin_lock_irq(cdev->ccwlock); - enabled = !!cdev->private->cmb; - spin_unlock_irq(cdev->ccwlock); - - return sprintf(buf, "%d\n", enabled); + return sprintf(buf, "%d\n", cmf_enabled(cdev)); } static ssize_t cmb_enable_store(struct device *dev, @@ -1202,15 +1208,20 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable) * @cdev: The ccw device to be enabled * * Returns %0 for success or a negative error value. - * + * Note: If this is called on a device for which channel measurement is already + * enabled a reset of the measurement data is triggered. * Context: * non-atomic */ int enable_cmf(struct ccw_device *cdev) { - int ret; + int ret = 0; device_lock(&cdev->dev); + if (cmf_enabled(cdev)) { + cmbops->reset(cdev); + goto out_unlock; + } get_device(&cdev->dev); ret = cmbops->alloc(cdev); if (ret) @@ -1229,7 +1240,7 @@ int enable_cmf(struct ccw_device *cdev) out: if (ret) put_device(&cdev->dev); - +out_unlock: device_unlock(&cdev->dev); return ret; } -- cgit v1.2.3-58-ga151 From 388b74d3a9f76abd349fe0b7ed8c58f88647111d Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 23 Jun 2016 11:09:26 +0200 Subject: s390/cio/device_ops: fix kernel doc Fix an incorrect kernel doc comment in device_ops.c. Also provide proper function markups while at it. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index a69f702a2fcc..877d9f601e63 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -97,7 +97,7 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) } /** - * ccw_device_is_pathgroup - determine if paths to this device are grouped + * ccw_device_is_pathgroup() - determine if paths to this device are grouped * @cdev: ccw device * * Return non-zero if there is a path group, zero otherwise. @@ -109,7 +109,7 @@ int ccw_device_is_pathgroup(struct ccw_device *cdev) EXPORT_SYMBOL(ccw_device_is_pathgroup); /** - * ccw_device_is_multipath - determine if device is operating in multipath mode + * ccw_device_is_multipath() - determine if device is operating in multipath mode * @cdev: ccw device * * Return non-zero if device is operating in multipath mode, zero otherwise. @@ -457,7 +457,7 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) } /** - * chp_get_chp_desc - return newly allocated channel-path descriptor + * ccw_device_get_chp_desc() - return newly allocated channel-path descriptor * @cdev: device to obtain the descriptor for * @chp_idx: index of the channel path * @@ -477,7 +477,7 @@ struct channel_path_desc *ccw_device_get_chp_desc(struct ccw_device *cdev, } /** - * ccw_device_get_id - obtain a ccw device id + * ccw_device_get_id() - obtain a ccw device id * @cdev: device to obtain the id for * @dev_id: where to fill in the values */ @@ -488,7 +488,7 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) EXPORT_SYMBOL(ccw_device_get_id); /** - * ccw_device_tm_start_key - perform start function + * ccw_device_tm_start_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -533,7 +533,7 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_key); /** - * ccw_device_tm_start_timeout_key - perform start function + * ccw_device_tm_start_timeout_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -559,7 +559,7 @@ int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); /** - * ccw_device_tm_start - perform start function + * ccw_device_tm_start() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -577,7 +577,7 @@ int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start); /** - * ccw_device_tm_start_timeout - perform start function + * ccw_device_tm_start_timeout() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -596,7 +596,7 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_timeout); /** - * ccw_device_get_mdc - accumulate max data count + * ccw_device_get_mdc() - accumulate max data count * @cdev: ccw device for which the max data count is accumulated * @mask: mask of paths to use * @@ -642,7 +642,7 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask) EXPORT_SYMBOL(ccw_device_get_mdc); /** - * ccw_device_tm_intrg - perform interrogate function + * ccw_device_tm_intrg() - perform interrogate function * @cdev: ccw device on which to perform the interrogate function * * Perform an interrogate function on the given ccw device. Return zero on @@ -664,7 +664,7 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) EXPORT_SYMBOL(ccw_device_tm_intrg); /** - * ccw_device_get_schid - obtain a subchannel id + * ccw_device_get_schid() - obtain a subchannel id * @cdev: device to obtain the id for * @schid: where to fill in the values */ -- cgit v1.2.3-58-ga151 From 6228c2a51edccf3e01fc4db065aac91b4cafdc76 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 21 Jun 2016 12:33:30 +0200 Subject: s390/chsc: fix ioctl CHSC_INFO_CU command Via CHSC_INFO_CU we ought to provide userspace with control unit configuration data. Due to an erroneous request code we trigger the wrong chsc command. Fix this copy and paste error. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc_sch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index b6f12c2bb114..735052ecd3e5 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -552,7 +552,7 @@ static int chsc_ioctl_info_cu(void __user *user_cd) goto out_free; } scucd_area->request.length = 0x0010; - scucd_area->request.code = 0x0028; + scucd_area->request.code = 0x0026; scucd_area->m = cd->m; scucd_area->fmt1 = cd->fmt; scucd_area->cssid = cd->cssid; -- cgit v1.2.3-58-ga151 From 0b601373778c770d7536b1d1761c3b2c06e4eb24 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 14 Jul 2016 11:30:37 +0200 Subject: s390/cio: make fmt1 channel path descriptor optional Not all machines / hypervisors support the chsc commands to fetch the fmt1 descriptor. When these commands fail the channel path would currently not be available to linux. Since users of these descriptors can already deal with invalid data make fetching it optional. The only data that is mandatory for us is the fmt0 channel path descriptor. Also make the return code for missing facilities in chsc_get_channel_measurement_chars consistent to other functions. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 11 +++++++---- drivers/s390/cio/chsc.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 50597f9522fe..d3b72eab2b8f 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -428,11 +428,14 @@ int chp_update_desc(struct channel_path *chp) if (rc) return rc; - rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); - if (rc) - return rc; + /* + * Fetching the following data is optional. Not all machines or + * hypervisors implement the required chsc commands. + */ + chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); + chsc_get_channel_measurement_chars(chp); - return chsc_get_channel_measurement_chars(chp); + return 0; } /** diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 452193f7298c..39bb2ea7b78f 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1020,7 +1020,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) chp->cmg = -1; if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm) - return 0; + return -EINVAL; spin_lock_irq(&chsc_page_lock); memset(chsc_page, 0, PAGE_SIZE); -- cgit v1.2.3-58-ga151 From f9773768f10c6af77778df67d6050778de42f120 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 21 Jun 2016 13:59:08 +0200 Subject: s390/chsc: sanitize fmt check for chp_desc determination When fetching channel path descriptors we've only evaluated the rfmt parameter which could lead us to trigger the chsc even though the machine doesn't support the specific format or to not trigger the chsc and report a failure to userspace even though the machine would've supported it. Improve these checks and change the parameters of the in-kernel user to be less confusing. Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 39bb2ea7b78f..4fe9531fb128 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -907,7 +907,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, struct chsc_scpd *scpd_area; int ccode, ret; - if ((rfmt == 1) && !css_general_characteristics.fcs) + if ((rfmt == 1 || rfmt == 0) && c == 1 && + !css_general_characteristics.fcs) return -EINVAL; if ((rfmt == 2) && !css_general_characteristics.cib) return -EINVAL; @@ -966,7 +967,7 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, spin_lock_irqsave(&chsc_page_lock, flags); scpd_area = chsc_page; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area); + ret = chsc_determine_channel_path_desc(chpid, 0, 1, 1, 0, scpd_area); if (ret) goto out; chsc_resp = (void *)&scpd_area->response; -- cgit v1.2.3-58-ga151 From 687cb7f21695469626f683d709d931ad41b2ca68 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 21 Jun 2016 16:26:25 +0200 Subject: s390/chsc: improve channel path descriptor determination When we fetch channel path descriptors via chsc we use a suboptimal struct chsc_scpd and adjust that by casting the response to a generic chsc_response_struct. Simplify the code by improving struct chsc_scpd. Signed-off-by: Sebastian Ott Reviewed-by: Cornelia Huck Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 10 ++++------ drivers/s390/cio/chsc.h | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 4fe9531fb128..940e725bde1e 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -940,7 +940,6 @@ EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); int chsc_determine_base_channel_path_desc(struct chp_id chpid, struct channel_path_desc *desc) { - struct chsc_response_struct *chsc_resp; struct chsc_scpd *scpd_area; unsigned long flags; int ret; @@ -950,8 +949,8 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid, ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area); if (ret) goto out; - chsc_resp = (void *)&scpd_area->response; - memcpy(desc, &chsc_resp->data, sizeof(*desc)); + + memcpy(desc, scpd_area->data, sizeof(*desc)); out: spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; @@ -960,7 +959,6 @@ out: int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, struct channel_path_desc_fmt1 *desc) { - struct chsc_response_struct *chsc_resp; struct chsc_scpd *scpd_area; unsigned long flags; int ret; @@ -970,8 +968,8 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, ret = chsc_determine_channel_path_desc(chpid, 0, 1, 1, 0, scpd_area); if (ret) goto out; - chsc_resp = (void *)&scpd_area->response; - memcpy(desc, &chsc_resp->data, sizeof(*desc)); + + memcpy(desc, scpd_area->data, sizeof(*desc)); out: spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 0de134c3a204..67c87b6e63ec 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -112,8 +112,9 @@ struct chsc_scpd { u32 last_chpid:8; u32 zeroes1; struct chsc_header response; - u8 data[PAGE_SIZE - 20]; -} __attribute__ ((packed)); + u32:32; + u8 data[0]; +} __packed; struct chsc_sda_area { struct chsc_header request; -- cgit v1.2.3-58-ga151 From 7b1058bc59ac24eb01e259749e8655fb884aa711 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Sat, 16 Jul 2016 14:18:34 +0530 Subject: s390/cio/chp : Remove deprecated create_singlethread_workqueue The workqueue "chp_wq" is involved in performing pending configure tasks for channel paths. It has a single work item(&cfg_work) and hence doesn't require ordering. Also, it is not being used on a memory reclaim path. Hence, the singlethreaded workqueue has been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. Signed-off-by: Bhaktipriya Shridhar Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index d3b72eab2b8f..e96aced58627 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -47,8 +47,6 @@ static DEFINE_MUTEX(info_lock); /* Time after which channel-path status may be outdated. */ static unsigned long chp_info_expires; -/* Workqueue to perform pending configure tasks. */ -static struct workqueue_struct *chp_wq; static struct work_struct cfg_work; /* Wait queue for configure completion events. */ @@ -717,7 +715,7 @@ static void cfg_func(struct work_struct *work) wake_up_interruptible(&cfg_wait_queue); return; } - queue_work(chp_wq, &cfg_work); + schedule_work(&cfg_work); } /** @@ -735,7 +733,7 @@ void chp_cfg_schedule(struct chp_id chpid, int configure) cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure); cfg_busy = 1; mutex_unlock(&cfg_lock); - queue_work(chp_wq, &cfg_work); + schedule_work(&cfg_work); } /** @@ -769,11 +767,6 @@ static int __init chp_init(void) ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw); if (ret) return ret; - chp_wq = create_singlethread_workqueue("cio_chp"); - if (!chp_wq) { - crw_unregister_handler(CRW_RSC_CPATH); - return -ENOMEM; - } INIT_WORK(&cfg_work, cfg_func); init_waitqueue_head(&cfg_wait_queue); if (info_update()) -- cgit v1.2.3-58-ga151