Эх сурвалжийг харах

Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (37 commits)
  [S390] Avoid excessive inlining.
  [S390] Mark kernel text section read-only.
  [S390] Convert memory detection into C code.
  [S390] Calibrate delay and bogomips.
  [S390] Hypervisor filesystem (s390_hypfs) for z/VM
  [S390] Add crypto support for 3592 tape devices
  [S390] boot from NSS support
  [S390] Support for s390 Pseudo Random Number Generator
  [S390] ETR support.
  [S390] noexec protection
  [S390] move crypto options and some cleanup.
  [S390] cio: Don't spam debug feature.
  [S390] Cleanup of CHSC event handling.
  [S390] cio: declare hardware structures packed.
  [S390] Add set_fs(USER_DS) to start_thread().
  [S390] cio: Catch operand exceptions on stsch.
  [S390] Fix register usage description.
  [S390] kretprobe_trampoline_holder() in wrong section.
  [S390] Fix kprobes breakpoint handling.
  [S390] Update maintainers file.
  ...
Linus Torvalds 18 жил өмнө
parent
commit
02aedd69e2
100 өөрчлөгдсөн 3690 нэмэгдсэн , 1596 устгасан
  1. 1 1
      Documentation/s390/Debugging390.txt
  2. 3 3
      MAINTAINERS
  3. 25 4
      arch/s390/Kconfig
  4. 1 1
      arch/s390/appldata/appldata_base.c
  5. 1 1
      arch/s390/appldata/appldata_mem.c
  6. 1 1
      arch/s390/appldata/appldata_net_sum.c
  7. 60 0
      arch/s390/crypto/Kconfig
  8. 1 2
      arch/s390/crypto/Makefile
  9. 23 24
      arch/s390/crypto/aes_s390.c
  10. 139 142
      arch/s390/crypto/crypt_s390.h
  11. 0 129
      arch/s390/crypto/crypt_s390_query.c
  12. 4 2
      arch/s390/crypto/des_check_key.c
  13. 4 4
      arch/s390/crypto/des_s390.c
  14. 213 0
      arch/s390/crypto/prng.c
  15. 37 46
      arch/s390/crypto/sha1_s390.c
  16. 3 8
      arch/s390/crypto/sha256_s390.c
  17. 7 5
      arch/s390/defconfig
  18. 1 1
      arch/s390/hypfs/Makefile
  19. 9 0
      arch/s390/hypfs/hypfs.h
  20. 0 16
      arch/s390/hypfs/hypfs_diag.h
  21. 231 0
      arch/s390/hypfs/hypfs_vm.c
  22. 21 10
      arch/s390/hypfs/inode.c
  23. 2 2
      arch/s390/kernel/Makefile
  24. 150 0
      arch/s390/kernel/base.S
  25. 1 1
      arch/s390/kernel/binfmt_elf32.c
  26. 2 3
      arch/s390/kernel/compat_exec_domain.c
  27. 16 8
      arch/s390/kernel/compat_linux.c
  28. 0 31
      arch/s390/kernel/compat_linux.h
  29. 4 4
      arch/s390/kernel/compat_signal.c
  30. 7 7
      arch/s390/kernel/cpcmd.c
  31. 1 0
      arch/s390/kernel/crash.c
  32. 8 10
      arch/s390/kernel/debug.c
  33. 306 0
      arch/s390/kernel/early.c
  34. 1 0
      arch/s390/kernel/ebcdic.c
  35. 7 187
      arch/s390/kernel/head31.S
  36. 3 190
      arch/s390/kernel/head64.S
  37. 95 11
      arch/s390/kernel/ipl.c
  38. 12 3
      arch/s390/kernel/irq.c
  39. 26 6
      arch/s390/kernel/kprobes.c
  40. 1 0
      arch/s390/kernel/machine_kexec.c
  41. 3 2
      arch/s390/kernel/module.c
  42. 2 2
      arch/s390/kernel/process.c
  43. 0 20
      arch/s390/kernel/profile.c
  44. 24 22
      arch/s390/kernel/ptrace.c
  45. 0 90
      arch/s390/kernel/reset.S
  46. 3 5
      arch/s390/kernel/s390_ext.c
  47. 133 22
      arch/s390/kernel/setup.c
  48. 1 1
      arch/s390/kernel/signal.c
  49. 12 20
      arch/s390/kernel/smp.c
  50. 5 5
      arch/s390/kernel/stacktrace.c
  51. 1119 66
      arch/s390/kernel/time.c
  52. 15 9
      arch/s390/kernel/traps.c
  53. 7 6
      arch/s390/kernel/vmlinux.lds.S
  54. 5 5
      arch/s390/kernel/vtime.c
  55. 1 1
      arch/s390/lib/Makefile
  56. 34 14
      arch/s390/lib/delay.c
  57. 77 0
      arch/s390/lib/qrnnd.S
  58. 23 0
      arch/s390/lib/uaccess.h
  59. 63 15
      arch/s390/lib/uaccess_mvcos.c
  60. 324 5
      arch/s390/lib/uaccess_pt.c
  61. 12 11
      arch/s390/lib/uaccess_std.c
  62. 1 1
      arch/s390/math-emu/Makefile
  63. 1 1
      arch/s390/math-emu/math.c
  64. 0 77
      arch/s390/math-emu/qrnnd.S
  65. 2 2
      arch/s390/mm/cmm.c
  66. 55 11
      arch/s390/mm/extmem.c
  67. 88 5
      arch/s390/mm/fault.c
  68. 8 12
      arch/s390/mm/init.c
  69. 7 7
      arch/s390/mm/vmem.c
  70. 0 49
      crypto/Kconfig
  71. 2 0
      drivers/crypto/Kconfig
  72. 0 8
      drivers/s390/Kconfig
  73. 2 0
      drivers/s390/Makefile
  74. 23 10
      drivers/s390/block/dasd.c
  75. 0 5
      drivers/s390/block/dasd_3990_erp.c
  76. 3 3
      drivers/s390/block/dasd_devmap.c
  77. 4 4
      drivers/s390/block/dasd_diag.c
  78. 33 62
      drivers/s390/block/dasd_eckd.c
  79. 17 7
      drivers/s390/block/dasd_eer.c
  80. 0 80
      drivers/s390/block/dasd_erp.c
  81. 2 2
      drivers/s390/block/dasd_fba.c
  82. 1 1
      drivers/s390/block/dasd_genhd.c
  83. 0 1
      drivers/s390/block/dasd_int.h
  84. 4 4
      drivers/s390/block/dasd_proc.c
  85. 3 3
      drivers/s390/block/dcssblk.c
  86. 2 2
      drivers/s390/char/Makefile
  87. 1 1
      drivers/s390/char/con3215.c
  88. 1 2
      drivers/s390/char/con3270.c
  89. 2 0
      drivers/s390/char/defkeymap.c
  90. 2 2
      drivers/s390/char/fs3270.c
  91. 2 0
      drivers/s390/char/keyboard.c
  92. 2 2
      drivers/s390/char/monwriter.c
  93. 2 2
      drivers/s390/char/raw3270.c
  94. 62 31
      drivers/s390/char/sclp.c
  95. 7 11
      drivers/s390/char/sclp.h
  96. 1 1
      drivers/s390/char/sclp_con.c
  97. 1 1
      drivers/s390/char/sclp_cpi.c
  98. 57 0
      drivers/s390/char/sclp_info.c
  99. 1 1
      drivers/s390/char/sclp_rw.c
  100. 1 1
      drivers/s390/char/sclp_tty.c

+ 1 - 1
Documentation/s390/Debugging390.txt

@@ -480,7 +480,7 @@ r2       argument 0 / return value 0                call-clobbered
 r3       argument 1 / return value 1 (if long long) call-clobbered
 r3       argument 1 / return value 1 (if long long) call-clobbered
 r4       argument 2                                 call-clobbered
 r4       argument 2                                 call-clobbered
 r5       argument 3                                 call-clobbered
 r5       argument 3                                 call-clobbered
-r6	 argument 5                                 saved
+r6	 argument 4				    saved
 r7       pointer-to arguments 5 to ...              saved      
 r7       pointer-to arguments 5 to ...              saved      
 r8       this & that                                saved
 r8       this & that                                saved
 r9       this & that                                saved
 r9       this & that                                saved

+ 3 - 3
MAINTAINERS

@@ -2791,7 +2791,7 @@ M:	schwidefsky@de.ibm.com
 P:	Heiko Carstens
 P:	Heiko Carstens
 M:	heiko.carstens@de.ibm.com
 M:	heiko.carstens@de.ibm.com
 M:	linux390@de.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 S:	Supported
 
 
@@ -2799,7 +2799,7 @@ S390 NETWORK DRIVERS
 P:	Frank Pavlic
 P:	Frank Pavlic
 M:	fpavlic@de.ibm.com
 M:	fpavlic@de.ibm.com
 M:	linux390@de.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 S:	Supported
 
 
@@ -2807,7 +2807,7 @@ S390 ZFCP DRIVER
 P:	Swen Schillig
 P:	Swen Schillig
 M:	swen@vnet.ibm.com
 M:	swen@vnet.ibm.com
 M:	linux390@de.ibm.com
 M:	linux390@de.ibm.com
-L:	linux-390@vm.marist.edu
+L:	linux-s390@vger.kernel.org
 W:	http://www.ibm.com/developerworks/linux/linux390/
 W:	http://www.ibm.com/developerworks/linux/linux390/
 S:	Supported
 S:	Supported
 
 

+ 25 - 4
arch/s390/Kconfig

@@ -34,10 +34,6 @@ config GENERIC_HWEIGHT
 	bool
 	bool
 	default y
 	default y
 
 
-config GENERIC_CALIBRATE_DELAY
-	bool
-	default y
-
 config GENERIC_TIME
 config GENERIC_TIME
 	def_bool y
 	def_bool y
 
 
@@ -134,6 +130,31 @@ config AUDIT_ARCH
 	bool
 	bool
 	default y
 	default y
 
 
+config S390_SWITCH_AMODE
+	bool "Switch kernel/user addressing modes"
+	help
+	  This option allows to switch the addressing modes of kernel and user
+	  space. The kernel parameter switch_amode=on will enable this feature,
+	  default is disabled. Enabling this (via kernel parameter) on machines
+	  earlier than IBM System z9-109 EC/BC will reduce system performance.
+
+	  Note that this option will also be selected by selecting the execute
+	  protection option below. Enabling the execute protection via the
+	  noexec kernel parameter will also switch the addressing modes,
+	  independent of the switch_amode kernel parameter.
+
+
+config S390_EXEC_PROTECT
+	bool "Data execute protection"
+	select S390_SWITCH_AMODE
+	help
+	  This option allows to enable a buffer overflow protection for user
+	  space programs and it also selects the addressing mode option above.
+	  The kernel parameter noexec=on will enable this feature and also
+	  switch the addressing modes, default is disabled. Enabling this (via
+	  kernel parameter) on machines earlier than IBM System z9-109 EC/BC
+	  will reduce system performance.
+
 comment "Code generation options"
 comment "Code generation options"
 
 
 choice
 choice

+ 1 - 1
arch/s390/appldata/appldata_base.c

@@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = {
 /*
 /*
  * Timer
  * Timer
  */
  */
-DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
+static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
 static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 
 
 static DEFINE_SPINLOCK(appldata_timer_lock);
 static DEFINE_SPINLOCK(appldata_timer_lock);

+ 1 - 1
arch/s390/appldata/appldata_mem.c

@@ -36,7 +36,7 @@
  * book:
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
  */
-struct appldata_mem_data {
+static struct appldata_mem_data {
 	u64 timestamp;
 	u64 timestamp;
 	u32 sync_count_1;       /* after VM collected the record data, */
 	u32 sync_count_1;       /* after VM collected the record data, */
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the

+ 1 - 1
arch/s390/appldata/appldata_net_sum.c

@@ -34,7 +34,7 @@
  * book:
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
  */
-struct appldata_net_sum_data {
+static struct appldata_net_sum_data {
 	u64 timestamp;
 	u64 timestamp;
 	u32 sync_count_1;	/* after VM collected the record data, */
 	u32 sync_count_1;	/* after VM collected the record data, */
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
 	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the

+ 60 - 0
arch/s390/crypto/Kconfig

@@ -0,0 +1,60 @@
+config CRYPTO_SHA1_S390
+	tristate "SHA1 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+	tristate "SHA256 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA256 secure hash standard (DFIPS 180-2).
+
+	  This version of SHA implements a 256 bit hash with 128 bits of
+	  security against collision attacks.
+
+config CRYPTO_DES_S390
+	tristate "DES and Triple DES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This us the s390 hardware accelerated implementation of the
+	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+	tristate "AES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+	  algorithm.
+
+	  Rijndael appears to be consistently a very good performer in
+	  both hardware and software across a wide range of computing
+	  environments regardless of its use in feedback or non-feedback
+	  modes. Its key setup time is excellent, and its key agility is
+	  good. Rijndael's very low memory requirements make it very well
+	  suited for restricted-space environments, in which it also
+	  demonstrates excellent performance. Rijndael's operations are
+	  among the easiest to defend against power and timing attacks.
+
+	  On s390 the System z9-109 currently only supports the key size
+	  of 128 bit.
+
+config S390_PRNG
+	tristate "Pseudo random number generator device driver"
+	depends on S390
+	default "m"
+	help
+	  Select this option if you want to use the s390 pseudo random number
+	  generator. The PRNG is part of the cryptograhic processor functions
+	  and uses triple-DES to generate secure random numbers like the
+	  ANSI X9.17 standard. The PRNG is usable via the char device
+	  /dev/prandom.

+ 1 - 2
arch/s390/crypto/Makefile

@@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
 obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
 obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
-
-obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
+obj-$(CONFIG_S390_PRNG) += prng.o

+ 23 - 24
arch/s390/crypto/aes_s390.c

@@ -4,7 +4,7 @@
  * s390 implementation of the AES Cipher Algorithm.
  * s390 implementation of the AES Cipher Algorithm.
  *
  *
  * s390 Version:
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  *
  * Derived from "crypto/aes.c"
  * Derived from "crypto/aes.c"
@@ -27,9 +27,11 @@
 /* data block size for all key lengths */
 /* data block size for all key lengths */
 #define AES_BLOCK_SIZE		16
 #define AES_BLOCK_SIZE		16
 
 
-int has_aes_128 = 0;
-int has_aes_192 = 0;
-int has_aes_256 = 0;
+#define AES_KEYLEN_128		1
+#define AES_KEYLEN_192		2
+#define AES_KEYLEN_256		4
+
+static char keylen_flag = 0;
 
 
 struct s390_aes_ctx {
 struct s390_aes_ctx {
 	u8 iv[AES_BLOCK_SIZE];
 	u8 iv[AES_BLOCK_SIZE];
@@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
 
 	switch (key_len) {
 	switch (key_len) {
 	case 16:
 	case 16:
-		if (!has_aes_128)
+		if (!(keylen_flag & AES_KEYLEN_128))
 			goto fail;
 			goto fail;
 		break;
 		break;
 	case 24:
 	case 24:
-		if (!has_aes_192)
+		if (!(keylen_flag & AES_KEYLEN_192))
 			goto fail;
 			goto fail;
 
 
 		break;
 		break;
 	case 32:
 	case 32:
-		if (!has_aes_256)
+		if (!(keylen_flag & AES_KEYLEN_256))
 			goto fail;
 			goto fail;
 		break;
 		break;
 	default:
 	default:
-		/* invalid key length */
 		goto fail;
 		goto fail;
 		break;
 		break;
 	}
 	}
@@ -322,34 +323,32 @@ static int __init aes_init(void)
 	int ret;
 	int ret;
 
 
 	if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
 	if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
-		has_aes_128 = 1;
+		keylen_flag |= AES_KEYLEN_128;
 	if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
 	if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
-		has_aes_192 = 1;
+		keylen_flag |= AES_KEYLEN_192;
 	if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
 	if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
-		has_aes_256 = 1;
+		keylen_flag |= AES_KEYLEN_256;
+
+	if (!keylen_flag)
+		return -EOPNOTSUPP;
 
 
-	if (!has_aes_128 && !has_aes_192 && !has_aes_256)
-		return -ENOSYS;
+	/* z9 109 and z9 BC/EC only support 128 bit key length */
+	if (keylen_flag == AES_KEYLEN_128)
+		printk(KERN_INFO
+		       "aes_s390: hardware acceleration only available for"
+		       "128 bit keys\n");
 
 
 	ret = crypto_register_alg(&aes_alg);
 	ret = crypto_register_alg(&aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto aes_err;
 		goto aes_err;
-	}
 
 
 	ret = crypto_register_alg(&ecb_aes_alg);
 	ret = crypto_register_alg(&ecb_aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO
-		       "crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto ecb_aes_err;
 		goto ecb_aes_err;
-	}
 
 
 	ret = crypto_register_alg(&cbc_aes_alg);
 	ret = crypto_register_alg(&cbc_aes_alg);
-	if (ret != 0) {
-		printk(KERN_INFO
-		       "crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
+	if (ret)
 		goto cbc_aes_err;
 		goto cbc_aes_err;
-	}
 
 
 out:
 out:
 	return ret;
 	return ret;

+ 139 - 142
arch/s390/crypto/crypt_s390.h

@@ -3,8 +3,9 @@
  *
  *
  * Support for s390 cryptographic instructions.
  * Support for s390 cryptographic instructions.
  *
  *
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -32,7 +33,8 @@ enum crypt_s390_operations {
 	CRYPT_S390_KMAC = 0x0500
 	CRYPT_S390_KMAC = 0x0500
 };
 };
 
 
-/* function codes for KM (CIPHER MESSAGE) instruction
+/*
+ * function codes for KM (CIPHER MESSAGE) instruction
  * 0x80 is the decipher modifier bit
  * 0x80 is the decipher modifier bit
  */
  */
 enum crypt_s390_km_func {
 enum crypt_s390_km_func {
@@ -51,7 +53,8 @@ enum crypt_s390_km_func {
 	KM_AES_256_DECRYPT  = CRYPT_S390_KM | 0x14 | 0x80,
 	KM_AES_256_DECRYPT  = CRYPT_S390_KM | 0x14 | 0x80,
 };
 };
 
 
-/* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
+/*
+ * function codes for KMC (CIPHER MESSAGE WITH CHAINING)
  * instruction
  * instruction
  */
  */
 enum crypt_s390_kmc_func {
 enum crypt_s390_kmc_func {
@@ -68,9 +71,11 @@ enum crypt_s390_kmc_func {
 	KMC_AES_192_DECRYPT  = CRYPT_S390_KMC | 0x13 | 0x80,
 	KMC_AES_192_DECRYPT  = CRYPT_S390_KMC | 0x13 | 0x80,
 	KMC_AES_256_ENCRYPT  = CRYPT_S390_KMC | 0x14,
 	KMC_AES_256_ENCRYPT  = CRYPT_S390_KMC | 0x14,
 	KMC_AES_256_DECRYPT  = CRYPT_S390_KMC | 0x14 | 0x80,
 	KMC_AES_256_DECRYPT  = CRYPT_S390_KMC | 0x14 | 0x80,
+	KMC_PRNG	     = CRYPT_S390_KMC | 0x43,
 };
 };
 
 
-/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+/*
+ * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
  * instruction
  * instruction
  */
  */
 enum crypt_s390_kimd_func {
 enum crypt_s390_kimd_func {
@@ -79,7 +84,8 @@ enum crypt_s390_kimd_func {
 	KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
 	KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
 };
 };
 
 
-/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
+/*
+ * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
  * instruction
  * instruction
  */
  */
 enum crypt_s390_klmd_func {
 enum crypt_s390_klmd_func {
@@ -88,7 +94,8 @@ enum crypt_s390_klmd_func {
 	KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
 	KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
 };
 };
 
 
-/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+/*
+ * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
  * instruction
  * instruction
  */
  */
 enum crypt_s390_kmac_func {
 enum crypt_s390_kmac_func {
@@ -98,229 +105,219 @@ enum crypt_s390_kmac_func {
 	KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
 	KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
 };
 };
 
 
-/* status word for s390 crypto instructions' QUERY functions */
-struct crypt_s390_query_status {
-	u64 high;
-	u64 low;
-};
-
-/*
+/**
+ * crypt_s390_km:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KM (CIPHER MESSAGE) operation of the CPU.
  * Executes the KM (CIPHER MESSAGE) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_km_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
  */
-static inline int
-crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int crypt_s390_km(long func, void *param,
+				u8 *dest, const u8 *src, long src_len)
 {
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
 	register long __src_len asm("3") = src_len;
-	register u8* __dest asm("4") = dest;
+	register u8 *__dest asm("4") = dest;
 	int ret;
 	int ret;
 
 
 	asm volatile(
 	asm volatile(
 		"0:	.insn	rre,0xb92e0000,%3,%1 \n" /* KM opcode */
 		"0:	.insn	rre,0xb92e0000,%3,%1 \n" /* KM opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h7\n"
-		"2:	ahi	%0,%h8\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 }
 
 
-/*
+/**
+ * crypt_s390_kmc:
+ * @func: the function code passed to KM; see crypt_s390_kmc_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
  * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kmc_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
  */
-static inline int
-crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int crypt_s390_kmc(long func, void *param,
+				 u8 *dest, const u8 *src, long src_len)
 {
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
 	register long __src_len asm("3") = src_len;
-	register u8* __dest asm("4") = dest;
+	register u8 *__dest asm("4") = dest;
 	int ret;
 	int ret;
 
 
 	asm volatile(
 	asm volatile(
 		"0:	.insn	rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
 		"0:	.insn	rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h7\n"
-		"2:	ahi	%0,%h8\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 }
 
 
-/*
+/**
+ * crypt_s390_kimd:
+ * @func: the function code passed to KM; see crypt_s390_kimd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
  * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
  * of the CPU.
  * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kimd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
  */
-static inline int
-crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kimd(long func, void *param,
+				  const u8 *src, long src_len)
 {
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
 	register long __src_len asm("3") = src_len;
 	int ret;
 	int ret;
 
 
 	asm volatile(
 	asm volatile(
 		"0:	.insn	rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
 		"0:	.insn	rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 }
 
 
-/*
+/**
+ * crypt_s390_klmd:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
  * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
  */
-static inline int
-crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_klmd(long func, void *param,
+				  const u8 *src, long src_len)
 {
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
 	register long __src_len asm("3") = src_len;
 	int ret;
 	int ret;
 
 
 	asm volatile(
 	asm volatile(
 		"0:	.insn	rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
 		"0:	.insn	rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 }
 
 
-/*
+/**
+ * crypt_s390_kmac:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
  * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
  * of the CPU.
  * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- * 	for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
  */
-static inline int
-crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kmac(long func, void *param,
+				  const u8 *src, long src_len)
 {
 {
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
 	register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-	register void* __param asm("1") = param;
-	register const u8* __src asm("2") = src;
+	register void *__param asm("1") = param;
+	register const u8 *__src asm("2") = src;
 	register long __src_len asm("3") = src_len;
 	register long __src_len asm("3") = src_len;
 	int ret;
 	int ret;
 
 
 	asm volatile(
 	asm volatile(
 		"0:	.insn	rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
 		"0:	.insn	rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
 		"1:	brc	1,0b \n" /* handle partial completion */
 		"1:	brc	1,0b \n" /* handle partial completion */
-		"	ahi	%0,%h6\n"
-		"2:	ahi	%0,%h7\n"
-		"3:\n"
-		EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+		"	la	%0,0\n"
+		"2:\n"
+		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
 		: "=d" (ret), "+a" (__src), "+d" (__src_len)
-		: "d" (__func), "a" (__param), "0" (-EFAULT),
-		  "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+		: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 	return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 }
 
 
 /**
 /**
+ * crypt_s390_func_available:
+ * @func: the function code of the specific function; 0 if op in general
+ *
  * Tests if a specific crypto function is implemented on the machine.
  * Tests if a specific crypto function is implemented on the machine.
- * @param func:	the function code of the specific function; 0 if op in general
- * @return	1 if func available; 0 if func or op in general not available
+ *
+ * Returns 1 if func available; 0 if func or op in general not available
  */
  */
-static inline int
-crypt_s390_func_available(int func)
+static inline int crypt_s390_func_available(int func)
 {
 {
+	unsigned char status[16];
 	int ret;
 	int ret;
 
 
-	struct crypt_s390_query_status status = {
-		.high = 0,
-		.low = 0
-	};
-	switch (func & CRYPT_S390_OP_MASK){
-		case CRYPT_S390_KM:
-			ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-			break;
-		case CRYPT_S390_KMC:
-			ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-			break;
-		case CRYPT_S390_KIMD:
-			ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-			break;
-		case CRYPT_S390_KLMD:
-			ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-			break;
-		case CRYPT_S390_KMAC:
-			ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-			break;
-		default:
-			ret = 0;
-			return ret;
-	}
-	if (ret >= 0){
-		func &= CRYPT_S390_FUNC_MASK;
-		func &= 0x7f; //mask modifier bit
-		if (func < 64){
-			ret = (status.high >> (64 - func - 1)) & 0x1;
-		} else {
-			ret = (status.low >> (128 - func - 1)) & 0x1;
-		}
-	} else {
-		ret = 0;
+	switch (func & CRYPT_S390_OP_MASK) {
+	case CRYPT_S390_KM:
+		ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
+		break;
+	case CRYPT_S390_KMC:
+		ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
+		break;
+	case CRYPT_S390_KIMD:
+		ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
+		break;
+	case CRYPT_S390_KLMD:
+		ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
+		break;
+	case CRYPT_S390_KMAC:
+		ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
+		break;
+	default:
+		return 0;
 	}
 	}
-	return ret;
+	if (ret < 0)
+		return 0;
+	func &= CRYPT_S390_FUNC_MASK;
+	func &= 0x7f;		/* mask modifier bit */
+	return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
 }
 }
 
 
-#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
+#endif	/* _CRYPTO_ARCH_S390_CRYPT_S390_H */

+ 0 - 129
arch/s390/crypto/crypt_s390_query.c

@@ -1,129 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for s390 cryptographic instructions.
- * Testing module for querying processor crypto capabilities.
- *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/errno.h>
-#include "crypt_s390.h"
-
-static void query_available_functions(void)
-{
-	printk(KERN_INFO "#####################\n");
-
-	/* query available KM functions */
-	printk(KERN_INFO "KM_QUERY: %d\n",
-		crypt_s390_func_available(KM_QUERY));
-	printk(KERN_INFO "KM_DEA: %d\n",
-		crypt_s390_func_available(KM_DEA_ENCRYPT));
-	printk(KERN_INFO "KM_TDEA_128: %d\n",
-		crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
-	printk(KERN_INFO "KM_TDEA_192: %d\n",
-		crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
-	printk(KERN_INFO "KM_AES_128: %d\n",
-		crypt_s390_func_available(KM_AES_128_ENCRYPT));
-	printk(KERN_INFO "KM_AES_192: %d\n",
-		crypt_s390_func_available(KM_AES_192_ENCRYPT));
-	printk(KERN_INFO "KM_AES_256: %d\n",
-		crypt_s390_func_available(KM_AES_256_ENCRYPT));
-
-	/* query available KMC functions */
-	printk(KERN_INFO "KMC_QUERY: %d\n",
-		crypt_s390_func_available(KMC_QUERY));
-	printk(KERN_INFO "KMC_DEA: %d\n",
-		crypt_s390_func_available(KMC_DEA_ENCRYPT));
-	printk(KERN_INFO "KMC_TDEA_128: %d\n",
-		crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
-	printk(KERN_INFO "KMC_TDEA_192: %d\n",
-		crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_128: %d\n",
-		crypt_s390_func_available(KMC_AES_128_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_192: %d\n",
-		crypt_s390_func_available(KMC_AES_192_ENCRYPT));
-	printk(KERN_INFO "KMC_AES_256: %d\n",
-		crypt_s390_func_available(KMC_AES_256_ENCRYPT));
-
-	/* query available KIMD functions */
-	printk(KERN_INFO "KIMD_QUERY: %d\n",
-		crypt_s390_func_available(KIMD_QUERY));
-	printk(KERN_INFO "KIMD_SHA_1: %d\n",
-		crypt_s390_func_available(KIMD_SHA_1));
-	printk(KERN_INFO "KIMD_SHA_256: %d\n",
-		crypt_s390_func_available(KIMD_SHA_256));
-
-	/* query available KLMD functions */
-	printk(KERN_INFO "KLMD_QUERY: %d\n",
-		crypt_s390_func_available(KLMD_QUERY));
-	printk(KERN_INFO "KLMD_SHA_1: %d\n",
-		crypt_s390_func_available(KLMD_SHA_1));
-	printk(KERN_INFO "KLMD_SHA_256: %d\n",
-		crypt_s390_func_available(KLMD_SHA_256));
-
-	/* query available KMAC functions */
-	printk(KERN_INFO "KMAC_QUERY: %d\n",
-		crypt_s390_func_available(KMAC_QUERY));
-	printk(KERN_INFO "KMAC_DEA: %d\n",
-		crypt_s390_func_available(KMAC_DEA));
-	printk(KERN_INFO "KMAC_TDEA_128: %d\n",
-		crypt_s390_func_available(KMAC_TDEA_128));
-	printk(KERN_INFO "KMAC_TDEA_192: %d\n",
-		crypt_s390_func_available(KMAC_TDEA_192));
-}
-
-static int init(void)
-{
-	struct crypt_s390_query_status status = {
-		.high = 0,
-		.low = 0
-	};
-
-	printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
-	crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-	printk(KERN_INFO "KM:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-	printk(KERN_INFO "KMC:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-	status.high = status.low = 0;
-	crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-	printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
-			(unsigned long long) status.high,
-			(unsigned long long) status.low);
-
-	query_available_functions();
-	return -ECANCELED;
-}
-
-static void __exit cleanup(void)
-{
-}
-
-module_init(init);
-module_exit(cleanup);
-
-MODULE_LICENSE("GPL");

+ 4 - 2
arch/s390/crypto/des_check_key.c

@@ -10,8 +10,9 @@
  * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
  * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
  *
  *
  * s390 Version:
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  *
  * Derived from "crypto/des.c"
  * Derived from "crypto/des.c"
  *   Copyright (c) 1992 Dana L. How.
  *   Copyright (c) 1992 Dana L. How.
@@ -30,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/crypto.h>
 #include <linux/crypto.h>
+#include "crypto_des.h"
 
 
 #define ROR(d,c,o)	((d) = (d) >> (c) | (d) << (o))
 #define ROR(d,c,o)	((d) = (d) >> (c) | (d) << (o))
 
 

+ 4 - 4
arch/s390/crypto/des_s390.c

@@ -3,9 +3,9 @@
  *
  *
  * s390 implementation of the DES Cipher Algorithm.
  * s390 implementation of the DES Cipher Algorithm.
  *
  *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ *	      Jan Glauber (jan.glauber@de.ibm.com)
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -557,7 +557,7 @@ static int init(void)
 	if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
 	if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
 	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
 
 	ret = crypto_register_alg(&des_alg);
 	ret = crypto_register_alg(&des_alg);
 	if (ret)
 	if (ret)

+ 213 - 0
arch/s390/crypto/prng.c

@@ -0,0 +1,213 @@
+/*
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ * Driver for the s390 pseudo random number generator
+ */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+
+#include "crypt_s390.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_DESCRIPTION("s390 PRNG interface");
+
+static int prng_chunk_size = 256;
+module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
+
+static int prng_entropy_limit = 4096;
+module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
+MODULE_PARM_DESC(prng_entropy_limit,
+	"PRNG add entropy after that much bytes were produced");
+
+/*
+ * Any one who considers arithmetical methods of producing random digits is,
+ * of course, in a state of sin. -- John von Neumann
+ */
+
+struct s390_prng_data {
+	unsigned long count; /* how many bytes were produced */
+	char *buf;
+};
+
+static struct s390_prng_data *p;
+
+/* copied from libica, use a non-zero initial parameter block */
+static unsigned char parm_block[32] = {
+0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
+0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+};
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static void prng_add_entropy(void)
+{
+	__u64 entropy[4];
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < 16; i++) {
+		ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
+				     (char *)entropy, sizeof(entropy));
+		BUG_ON(ret < 0 || ret != sizeof(entropy));
+		memcpy(parm_block, entropy, sizeof(entropy));
+	}
+}
+
+static void prng_seed(int nbytes)
+{
+	char buf[16];
+	int i = 0;
+
+	BUG_ON(nbytes > 16);
+	get_random_bytes(buf, nbytes);
+
+	/* Add the entropy */
+	while (nbytes >= 8) {
+		*((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+		prng_add_entropy();
+		i += 8;
+		nbytes -= 8;
+	}
+	prng_add_entropy();
+}
+
+static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+			 loff_t *ppos)
+{
+	int chunk, n;
+	int ret = 0;
+	int tmp;
+
+	/* nbytes can be arbitrary long, we spilt it into chunks */
+	while (nbytes) {
+		/* same as in extract_entropy_user in random.c */
+		if (need_resched()) {
+			if (signal_pending(current)) {
+				if (ret == 0)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+
+		/*
+		 * we lose some random bytes if an attacker issues
+		 * reads < 8 bytes, but we don't care
+		 */
+		chunk = min_t(int, nbytes, prng_chunk_size);
+
+		/* PRNG only likes multiples of 8 bytes */
+		n = (chunk + 7) & -8;
+
+		if (p->count > prng_entropy_limit)
+			prng_seed(8);
+
+		/* if the CPU supports PRNG stckf is present too */
+		asm volatile(".insn     s,0xb27c0000,%0"
+			     : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+
+		/*
+		 * Beside the STCKF the input for the TDES-EDE is the output
+		 * of the last operation. We differ here from X9.17 since we
+		 * only store one timestamp into the buffer. Padding the whole
+		 * buffer with timestamps does not improve security, since
+		 * successive stckf have nearly constant offsets.
+		 * If an attacker knows the first timestamp it would be
+		 * trivial to guess the additional values. One timestamp
+		 * is therefore enough and still guarantees unique input values.
+		 *
+		 * Note: you can still get strict X9.17 conformity by setting
+		 * prng_chunk_size to 8 bytes.
+		*/
+		tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
+		BUG_ON((tmp < 0) || (tmp != n));
+
+		p->count += n;
+
+		if (copy_to_user(ubuf, p->buf, chunk))
+			return -EFAULT;
+
+		nbytes -= chunk;
+		ret += chunk;
+		ubuf += chunk;
+	}
+	return ret;
+}
+
+static struct file_operations prng_fops = {
+	.owner		= THIS_MODULE,
+	.open		= &prng_open,
+	.release	= NULL,
+	.read		= &prng_read,
+};
+
+static struct miscdevice prng_dev = {
+	.name	= "prandom",
+	.minor	= MISC_DYNAMIC_MINOR,
+	.fops	= &prng_fops,
+};
+
+static int __init prng_init(void)
+{
+	int ret;
+
+	/* check if the CPU has a PRNG */
+	if (!crypt_s390_func_available(KMC_PRNG))
+		return -EOPNOTSUPP;
+
+	if (prng_chunk_size < 8)
+		return -EINVAL;
+
+	p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	p->count = 0;
+
+	p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
+	if (!p->buf) {
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	/* initialize the PRNG, add 128 bits of entropy */
+	prng_seed(16);
+
+	ret = misc_register(&prng_dev);
+	if (ret) {
+		printk(KERN_WARNING
+		       "Could not register misc device for PRNG.\n");
+		goto out_buf;
+	}
+	return 0;
+
+out_buf:
+	kfree(p->buf);
+out_free:
+	kfree(p);
+	return ret;
+}
+
+static void __exit prng_exit(void)
+{
+	/* wipe me */
+	memset(p->buf, 0, prng_chunk_size);
+	kfree(p->buf);
+	kfree(p);
+
+	misc_deregister(&prng_dev);
+}
+
+module_init(prng_init);
+module_exit(prng_exit);

+ 37 - 46
arch/s390/crypto/sha1_s390.c

@@ -8,8 +8,9 @@
  * implementation written by Steve Reid.
  * implementation written by Steve Reid.
  *
  *
  * s390 Version:
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *		Jan Glauber (jan.glauber@de.ibm.com)
  *
  *
  * Derived from "crypto/sha1.c"
  * Derived from "crypto/sha1.c"
  *   Copyright (c) Alan Smithee.
  *   Copyright (c) Alan Smithee.
@@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx {
 static void sha1_init(struct crypto_tfm *tfm)
 static void sha1_init(struct crypto_tfm *tfm)
 {
 {
 	struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
-	static const u32 initstate[5] = {
-		0x67452301,
-		0xEFCDAB89,
-		0x98BADCFE,
-		0x10325476,
-		0xC3D2E1F0
-	};
+
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] =	0xEFCDAB89;
+	ctx->state[2] =	0x98BADCFE;
+	ctx->state[3] = 0x10325476;
+	ctx->state[4] =	0xC3D2E1F0;
 
 
 	ctx->count = 0;
 	ctx->count = 0;
-	memcpy(ctx->state, &initstate, sizeof(initstate));
 	ctx->buf_len = 0;
 	ctx->buf_len = 0;
 }
 }
 
 
@@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
 	long imd_len;
 	long imd_len;
 
 
 	sctx = crypto_tfm_ctx(tfm);
 	sctx = crypto_tfm_ctx(tfm);
-	sctx->count += len * 8; //message bit length
+	sctx->count += len * 8; /* message bit length */
 
 
-	//anything in buffer yet? -> must be completed
+	/* anything in buffer yet? -> must be completed */
 	if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
 	if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
-		//complete full block and hash
+		/* complete full block and hash */
 		memcpy(sctx->buffer + sctx->buf_len, data,
 		memcpy(sctx->buffer + sctx->buf_len, data,
-				SHA1_BLOCK_SIZE - sctx->buf_len);
+		       SHA1_BLOCK_SIZE - sctx->buf_len);
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
 				SHA1_BLOCK_SIZE);
 				SHA1_BLOCK_SIZE);
 		data += SHA1_BLOCK_SIZE - sctx->buf_len;
 		data += SHA1_BLOCK_SIZE - sctx->buf_len;
@@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
 		sctx->buf_len = 0;
 		sctx->buf_len = 0;
 	}
 	}
 
 
-	//rest of data contains full blocks?
+	/* rest of data contains full blocks? */
 	imd_len = len & ~0x3ful;
 	imd_len = len & ~0x3ful;
-	if (imd_len){
+	if (imd_len) {
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
 		crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
 		data += imd_len;
 		data += imd_len;
 		len -= imd_len;
 		len -= imd_len;
 	}
 	}
-	//anything left? store in buffer
-	if (len){
+	/* anything left? store in buffer */
+	if (len) {
 		memcpy(sctx->buffer + sctx->buf_len , data, len);
 		memcpy(sctx->buffer + sctx->buf_len , data, len);
 		sctx->buf_len += len;
 		sctx->buf_len += len;
 	}
 	}
 }
 }
 
 
 
 
-static void
-pad_message(struct crypt_s390_sha1_ctx* sctx)
+static void pad_message(struct crypt_s390_sha1_ctx* sctx)
 {
 {
 	int index;
 	int index;
 
 
 	index = sctx->buf_len;
 	index = sctx->buf_len;
-	sctx->buf_len = (sctx->buf_len < 56)?
-		SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
-	//start pad with 1
+	sctx->buf_len = (sctx->buf_len < 56) ?
+			 SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
+	/* start pad with 1 */
 	sctx->buffer[index] = 0x80;
 	sctx->buffer[index] = 0x80;
-	//pad with zeros
+	/* pad with zeros */
 	index++;
 	index++;
 	memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
 	memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
-	//append length
+	/* append length */
 	memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
 	memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
-			sizeof sctx->count);
+	       sizeof sctx->count);
 }
 }
 
 
 /* Add padding and return the message digest. */
 /* Add padding and return the message digest. */
@@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
 {
 {
 	struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 	struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 
 
-	//must perform manual padding
+	/* must perform manual padding */
 	pad_message(sctx);
 	pad_message(sctx);
 	crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
 	crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
-	//copy digest to out
+	/* copy digest to out */
 	memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
 	memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
-	/* Wipe context */
+	/* wipe context */
 	memset(sctx, 0, sizeof *sctx);
 	memset(sctx, 0, sizeof *sctx);
 }
 }
 
 
 static struct crypto_alg alg = {
 static struct crypto_alg alg = {
 	.cra_name	=	"sha1",
 	.cra_name	=	"sha1",
-	.cra_driver_name =	"sha1-s390",
+	.cra_driver_name=	"sha1-s390",
 	.cra_priority	=	CRYPT_S390_PRIORITY,
 	.cra_priority	=	CRYPT_S390_PRIORITY,
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
 	.cra_blocksize	=	SHA1_BLOCK_SIZE,
 	.cra_blocksize	=	SHA1_BLOCK_SIZE,
 	.cra_ctxsize	=	sizeof(struct crypt_s390_sha1_ctx),
 	.cra_ctxsize	=	sizeof(struct crypt_s390_sha1_ctx),
 	.cra_module	=	THIS_MODULE,
 	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA1_DIGEST_SIZE,
 	.dia_digestsize	=	SHA1_DIGEST_SIZE,
-	.dia_init   	= 	sha1_init,
-	.dia_update 	=	sha1_update,
-	.dia_final  	=	sha1_final } }
+	.dia_init	=	sha1_init,
+	.dia_update	=	sha1_update,
+	.dia_final	=	sha1_final } }
 };
 };
 
 
-static int
-init(void)
+static int __init init(void)
 {
 {
-	int ret = -ENOSYS;
+	if (!crypt_s390_func_available(KIMD_SHA_1))
+		return -EOPNOTSUPP;
 
 
-	if (crypt_s390_func_available(KIMD_SHA_1)){
-		ret = crypto_register_alg(&alg);
-		if (ret == 0){
-			printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
-		}
-	}
-	return ret;
+	return crypto_register_alg(&alg);
 }
 }
 
 
-static void __exit
-fini(void)
+static void __exit fini(void)
 {
 {
 	crypto_unregister_alg(&alg);
 	crypto_unregister_alg(&alg);
 }
 }

+ 3 - 8
arch/s390/crypto/sha256_s390.c

@@ -4,7 +4,7 @@
  * s390 implementation of the SHA256 Secure Hash Algorithm.
  * s390 implementation of the SHA256 Secure Hash Algorithm.
  *
  *
  * s390 Version:
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  *
  * Derived from "crypto/sha256.c"
  * Derived from "crypto/sha256.c"
@@ -143,15 +143,10 @@ static struct crypto_alg alg = {
 
 
 static int init(void)
 static int init(void)
 {
 {
-	int ret;
-
 	if (!crypt_s390_func_available(KIMD_SHA_256))
 	if (!crypt_s390_func_available(KIMD_SHA_256))
-		return -ENOSYS;
+		return -EOPNOTSUPP;
 
 
-	ret = crypto_register_alg(&alg);
-	if (ret != 0)
-		printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
-	return ret;
+	return crypto_register_alg(&alg);
 }
 }
 
 
 static void __exit fini(void)
 static void __exit fini(void)

+ 7 - 5
arch/s390/defconfig

@@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000
 CONFIG_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_AUDIT_ARCH=y
 CONFIG_AUDIT_ARCH=y
+CONFIG_S390_SWITCH_AMODE=y
+CONFIG_S390_EXEC_PROTECT=y
 
 
 #
 #
 # Code generation options
 # Code generation options
@@ -431,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y
 CONFIG_TN3215=y
 CONFIG_TN3215=y
 CONFIG_TN3215_CONSOLE=y
 CONFIG_TN3215_CONSOLE=y
 CONFIG_CCW_CONSOLE=y
 CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_CONSOLE=y
 CONFIG_SCLP_CONSOLE=y
 CONFIG_SCLP_VT220_TTY=y
 CONFIG_SCLP_VT220_TTY=y
@@ -724,9 +725,7 @@ CONFIG_CRYPTO_MANAGER=y
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA1_S390 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA256_S390 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
 # CONFIG_CRYPTO_TGR192 is not set
@@ -735,12 +734,10 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_CBC=y
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_DES is not set
 # CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_DES_S390 is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
 # CONFIG_CRYPTO_SERPENT is not set
 # CONFIG_CRYPTO_AES is not set
 # CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_AES_S390 is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
 # CONFIG_CRYPTO_CAST6 is not set
 # CONFIG_CRYPTO_TEA is not set
 # CONFIG_CRYPTO_TEA is not set
@@ -755,6 +752,11 @@ CONFIG_CRYPTO_CBC=y
 #
 #
 # Hardware crypto devices
 # Hardware crypto devices
 #
 #
+# CONFIG_CRYPTO_SHA1_S390 is not set
+# CONFIG_CRYPTO_SHA256_S390 is not set
+# CONFIG_CRYPTO_DES_S390 is not set
+# CONFIG_CRYPTO_AES_S390 is not set
+CONFIG_S390_PRNG=m
 
 
 #
 #
 # Library routines
 # Library routines

+ 1 - 1
arch/s390/hypfs/Makefile

@@ -4,4 +4,4 @@
 
 
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 
 
-s390_hypfs-objs := inode.o hypfs_diag.o
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o

+ 9 - 0
arch/s390/hypfs/hypfs.h

@@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb,
 				       struct dentry *dir, const char *name,
 				       struct dentry *dir, const char *name,
 				       char *string);
 				       char *string);
 
 
+/* LPAR Hypervisor */
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+/* VM Hypervisor */
+extern int hypfs_vm_init(void);
+extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+
 #endif /* _HYPFS_H_ */
 #endif /* _HYPFS_H_ */

+ 0 - 16
arch/s390/hypfs/hypfs_diag.h

@@ -1,16 +0,0 @@
-/*
- *  arch/s390/hypfs_diag.h
- *    Hypervisor filesystem for Linux on s390.
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#ifndef _HYPFS_DIAG_H_
-#define _HYPFS_DIAG_H_
-
-extern int hypfs_diag_init(void);
-extern void hypfs_diag_exit(void);
-extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
-
-#endif /* _HYPFS_DIAG_H_ */

+ 231 - 0
arch/s390/hypfs/hypfs_vm.c

@@ -0,0 +1,231 @@
+/*
+ *    Hypervisor filesystem for Linux on s390. z/VM implementation.
+ *
+ *    Copyright (C) IBM Corp. 2006
+ *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define NAME_LEN 8
+
+static char local_guest[] = "        ";
+static char all_guests[] = "*       ";
+static char *guest_query;
+
+struct diag2fc_data {
+	__u32 version;
+	__u32 flags;
+	__u64 used_cpu;
+	__u64 el_time;
+	__u64 mem_min_kb;
+	__u64 mem_max_kb;
+	__u64 mem_share_kb;
+	__u64 mem_used_kb;
+	__u32 pcpus;
+	__u32 lcpus;
+	__u32 vcpus;
+	__u32 cpu_min;
+	__u32 cpu_max;
+	__u32 cpu_shares;
+	__u32 cpu_use_samp;
+	__u32 cpu_delay_samp;
+	__u32 page_wait_samp;
+	__u32 idle_samp;
+	__u32 other_samp;
+	__u32 total_samp;
+	char  guest_name[NAME_LEN];
+};
+
+struct diag2fc_parm_list {
+	char userid[NAME_LEN];
+	char aci_grp[NAME_LEN];
+	__u64 addr;
+	__u32 size;
+	__u32 fmt;
+};
+
+static int diag2fc(int size, char* query, void *addr)
+{
+	unsigned long residual_cnt;
+	unsigned long rc;
+	struct diag2fc_parm_list parm_list;
+
+	memcpy(parm_list.userid, query, NAME_LEN);
+	ASCEBC(parm_list.userid, NAME_LEN);
+	parm_list.addr = (unsigned long) addr ;
+	parm_list.size = size;
+	parm_list.fmt = 0x02;
+	memset(parm_list.aci_grp, 0x40, NAME_LEN);
+	rc = -1;
+
+	asm volatile(
+		"	diag    %0,%1,0x2fc\n"
+		"0:\n"
+		EX_TABLE(0b,0b)
+		: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
+
+	if ((rc != 0 ) && (rc != -2))
+		return rc;
+	else
+		return -residual_cnt;
+}
+
+static struct diag2fc_data *diag2fc_store(char *query, int *count)
+{
+	int size;
+	struct diag2fc_data *data;
+
+	do {
+		size = diag2fc(0, query, NULL);
+		if (size < 0)
+			return ERR_PTR(-EACCES);
+		data = vmalloc(size);
+		if (!data)
+			return ERR_PTR(-ENOMEM);
+		if (diag2fc(size, query, data) == 0)
+			break;
+		vfree(data);
+	} while (1);
+	*count = (size / sizeof(*data));
+
+	return data;
+}
+
+static void diag2fc_free(void *data)
+{
+	vfree(data);
+}
+
+#define ATTRIBUTE(sb, dir, name, member) \
+do { \
+	void *rc; \
+	rc = hypfs_create_u64(sb, dir, name, member); \
+	if (IS_ERR(rc)) \
+		return PTR_ERR(rc); \
+} while(0)
+
+static int hpyfs_vm_create_guest(struct super_block *sb,
+				 struct dentry *systems_dir,
+				 struct diag2fc_data *data)
+{
+	char guest_name[NAME_LEN + 1] = {};
+	struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
+	int dedicated_flag, capped_value;
+
+	capped_value = (data->flags & 0x00000006) >> 1;
+	dedicated_flag = (data->flags & 0x00000008) >> 3;
+
+	/* guest dir */
+	memcpy(guest_name, data->guest_name, NAME_LEN);
+	EBCASC(guest_name, NAME_LEN);
+	strstrip(guest_name);
+	guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
+	if (IS_ERR(guest_dir))
+		return PTR_ERR(guest_dir);
+	ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
+
+	/* logical cpu information */
+	cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
+	if (IS_ERR(cpus_dir))
+		return PTR_ERR(cpus_dir);
+	ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
+	ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
+	ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
+	ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
+	ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
+	ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
+	ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
+
+	/* memory information */
+	mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
+	if (IS_ERR(mem_dir))
+		return PTR_ERR(mem_dir);
+	ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
+	ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
+	ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
+	ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
+
+	/* samples */
+	samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
+	if (IS_ERR(samples_dir))
+		return PTR_ERR(samples_dir);
+	ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
+	ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
+	ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
+	ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
+	ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
+	ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
+	return 0;
+}
+
+int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
+{
+	struct dentry *dir, *file;
+	struct diag2fc_data *data;
+	int rc, i, count = 0;
+
+	data = diag2fc_store(guest_query, &count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	/* Hpervisor Info */
+	dir = hypfs_mkdir(sb, root, "hyp");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+	file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
+	if (IS_ERR(file)) {
+		rc = PTR_ERR(file);
+		goto failed;
+	}
+
+	/* physical cpus */
+	dir = hypfs_mkdir(sb, root, "cpus");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+	file = hypfs_create_u64(sb, dir, "count", data->lcpus);
+	if (IS_ERR(file)) {
+		rc = PTR_ERR(file);
+		goto failed;
+	}
+
+	/* guests */
+	dir = hypfs_mkdir(sb, root, "systems");
+	if (IS_ERR(dir)) {
+		rc = PTR_ERR(dir);
+		goto failed;
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
+		if (rc)
+			goto failed;
+	}
+	diag2fc_free(data);
+	return 0;
+
+failed:
+	diag2fc_free(data);
+	return rc;
+}
+
+int hypfs_vm_init(void)
+{
+	if (diag2fc(0, all_guests, NULL) > 0)
+		guest_query = all_guests;
+	else if (diag2fc(0, local_guest, NULL) > 0)
+		guest_query = local_guest;
+	else
+		return -EACCES;
+
+	return 0;
+}

+ 21 - 10
arch/s390/hypfs/inode.c

@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <asm/ebcdic.h>
 #include <asm/ebcdic.h>
 #include "hypfs.h"
 #include "hypfs.h"
-#include "hypfs_diag.h"
 
 
 #define HYPFS_MAGIC 0x687970	/* ASCII 'hyp' */
 #define HYPFS_MAGIC 0x687970	/* ASCII 'hyp' */
 #define TMP_SIZE 64		/* size of temporary buffers */
 #define TMP_SIZE 64		/* size of temporary buffers */
@@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
 		goto out;
 		goto out;
 	}
 	}
 	hypfs_delete_tree(sb->s_root);
 	hypfs_delete_tree(sb->s_root);
-	rc = hypfs_diag_create_files(sb, sb->s_root);
+	if (MACHINE_IS_VM)
+		rc = hypfs_vm_create_files(sb, sb->s_root);
+	else
+		rc = hypfs_diag_create_files(sb, sb->s_root);
 	if (rc) {
 	if (rc) {
 		printk(KERN_ERR "hypfs: Update failed\n");
 		printk(KERN_ERR "hypfs: Update failed\n");
 		hypfs_delete_tree(sb->s_root);
 		hypfs_delete_tree(sb->s_root);
@@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
 		rc = -ENOMEM;
 		rc = -ENOMEM;
 		goto err_alloc;
 		goto err_alloc;
 	}
 	}
-	rc = hypfs_diag_create_files(sb, root_dentry);
+	if (MACHINE_IS_VM)
+		rc = hypfs_vm_create_files(sb, root_dentry);
+	else
+		rc = hypfs_diag_create_files(sb, root_dentry);
 	if (rc)
 	if (rc)
 		goto err_tree;
 		goto err_tree;
 	sbi->update_file = hypfs_create_update_file(sb, root_dentry);
 	sbi->update_file = hypfs_create_update_file(sb, root_dentry);
@@ -462,11 +467,15 @@ static int __init hypfs_init(void)
 {
 {
 	int rc;
 	int rc;
 
 
-	if (MACHINE_IS_VM)
-		return -ENODATA;
-	if (hypfs_diag_init()) {
-		rc = -ENODATA;
-		goto fail_diag;
+	if (MACHINE_IS_VM) {
+		if (hypfs_vm_init())
+			/* no diag 2fc, just exit */
+			return -ENODATA;
+	} else {
+		if (hypfs_diag_init()) {
+			rc = -ENODATA;
+			goto fail_diag;
+		}
 	}
 	}
 	kset_set_kset_s(&s390_subsys, hypervisor_subsys);
 	kset_set_kset_s(&s390_subsys, hypervisor_subsys);
 	rc = subsystem_register(&s390_subsys);
 	rc = subsystem_register(&s390_subsys);
@@ -480,7 +489,8 @@ static int __init hypfs_init(void)
 fail_filesystem:
 fail_filesystem:
 	subsystem_unregister(&s390_subsys);
 	subsystem_unregister(&s390_subsys);
 fail_sysfs:
 fail_sysfs:
-	hypfs_diag_exit();
+	if (!MACHINE_IS_VM)
+		hypfs_diag_exit();
 fail_diag:
 fail_diag:
 	printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
 	printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
 	return rc;
 	return rc;
@@ -488,7 +498,8 @@ fail_diag:
 
 
 static void __exit hypfs_exit(void)
 static void __exit hypfs_exit(void)
 {
 {
-	hypfs_diag_exit();
+	if (!MACHINE_IS_VM)
+		hypfs_diag_exit();
 	unregister_filesystem(&hypfs_type);
 	unregister_filesystem(&hypfs_type);
 	subsystem_unregister(&s390_subsys);
 	subsystem_unregister(&s390_subsys);
 }
 }

+ 2 - 2
arch/s390/kernel/Makefile

@@ -4,9 +4,9 @@
 
 
 EXTRA_AFLAGS	:= -traditional
 EXTRA_AFLAGS	:= -traditional
 
 
-obj-y	:=  bitmap.o traps.o time.o process.o reset.o \
+obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-	    semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
+	    semaphore.o s390_ext.o debug.o irq.o ipl.o
 
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)

+ 150 - 0
arch/s390/kernel/base.S

@@ -0,0 +1,150 @@
+/*
+ *  arch/s390/kernel/base.S
+ *
+ *    Copyright IBM Corp. 2006,2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *		 Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_64BIT
+
+	.globl	s390_base_mcck_handler
+s390_base_mcck_handler:
+	basr	%r13,0
+0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
+	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_mcck_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	la	%r1,4095
+	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+	lpswe	__LC_MCK_OLD_PSW
+
+	.section .bss
+	.globl	s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+	.quad	0
+	.previous
+
+	.globl	s390_base_ext_handler
+s390_base_ext_handler:
+	stmg	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_ext_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lmg	%r0,%r15,__LC_SAVE_AREA
+	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
+	lpswe	__LC_EXT_OLD_PSW
+
+	.section .bss
+	.globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+	.quad	0
+	.previous
+
+	.globl	s390_base_pgm_handler
+s390_base_pgm_handler:
+	stmg	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	aghi	%r15,-STACK_FRAME_OVERHEAD
+	larl	%r1,s390_base_pgm_handler_fn
+	lg	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+	lmg	%r0,%r15,__LC_SAVE_AREA
+	lpswe	__LC_PGM_OLD_PSW
+1:	lpswe	disabled_wait_psw-0b(%r13)
+
+	.align	8
+disabled_wait_psw:
+	.quad	0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
+
+	.section .bss
+	.globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+	.quad	0
+	.previous
+
+#else /* CONFIG_64BIT */
+
+	.globl	s390_base_mcck_handler
+s390_base_mcck_handler:
+	basr	%r13,0
+0:	l	%r15,__LC_PANIC_STACK	# load panic stack
+	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lm	%r0,%r15,__LC_GPREGS_SAVE_AREA
+	lpsw	__LC_MCK_OLD_PSW
+
+2:	.long	s390_base_mcck_handler_fn
+
+	.section .bss
+	.globl	s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+	.long	0
+	.previous
+
+	.globl	s390_base_ext_handler
+s390_base_ext_handler:
+	stm	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+1:	lm	%r0,%r15,__LC_SAVE_AREA
+	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
+	lpsw	__LC_EXT_OLD_PSW
+
+2:	.long	s390_base_ext_handler_fn
+
+	.section .bss
+	.globl	s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+	.long	0
+	.previous
+
+	.globl	s390_base_pgm_handler
+s390_base_pgm_handler:
+	stm	%r0,%r15,__LC_SAVE_AREA
+	basr	%r13,0
+0:	ahi	%r15,-STACK_FRAME_OVERHEAD
+	l	%r1,2f-0b(%r13)
+	l	%r1,0(%r1)
+	ltr	%r1,%r1
+	jz	1f
+	basr	%r14,%r1
+	lm	%r0,%r15,__LC_SAVE_AREA
+	lpsw	__LC_PGM_OLD_PSW
+
+1:	lpsw	disabled_wait_psw-0b(%r13)
+
+2:	.long	s390_base_pgm_handler_fn
+
+disabled_wait_psw:
+	.align	8
+	.long	0x000a0000,0x00000000 + s390_base_pgm_handler
+
+	.section .bss
+	.globl	s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+	.long	0
+	.previous
+
+#endif /* CONFIG_64BIT */

+ 1 - 1
arch/s390/kernel/binfmt_elf32.c

@@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
 
 
 #undef cputime_to_timeval
 #undef cputime_to_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
+static inline void
 cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
 cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
 {
 {
 	value->tv_usec = cputime % 1000000;
 	value->tv_usec = cputime % 1000000;

+ 2 - 3
arch/s390/kernel/compat_exec_domain.c

@@ -12,10 +12,9 @@
 #include <linux/personality.h>
 #include <linux/personality.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 
 
-struct exec_domain s390_exec_domain;
+static struct exec_domain s390_exec_domain;
 
 
-static int __init
-s390_init (void)
+static int __init s390_init (void)
 {
 {
 	s390_exec_domain.name = "Linux/s390";
 	s390_exec_domain.name = "Linux/s390";
 	s390_exec_domain.handler = NULL;
 	s390_exec_domain.handler = NULL;

+ 16 - 8
arch/s390/kernel/compat_linux.c

@@ -69,6 +69,12 @@
 
 
 #include "compat_linux.h"
 #include "compat_linux.h"
 
 
+long psw_user32_bits	= (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			   PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			   PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+long psw32_user_bits	= (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
+			   PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+			   PSW32_MASK_PSTATE);
  
  
 /* For this source file, we want overflow handling. */
 /* For this source file, we want overflow handling. */
 
 
@@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
 	mm_segment_t old_fs = get_fs ();
 	mm_segment_t old_fs = get_fs ();
 	
 	
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	ret = sys_sysinfo((struct sysinfo __user *) &s);
+	ret = sys_sysinfo((struct sysinfo __force __user *) &s);
 	set_fs (old_fs);
 	set_fs (old_fs);
 	err = put_user (s.uptime, &info->uptime);
 	err = put_user (s.uptime, &info->uptime);
 	err |= __put_user (s.loads[0], &info->loads[0]);
 	err |= __put_user (s.loads[0], &info->loads[0]);
@@ -445,7 +451,8 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 	mm_segment_t old_fs = get_fs ();
 	mm_segment_t old_fs = get_fs ();
 	
 	
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
+	ret = sys_sched_rr_get_interval(pid,
+					(struct timespec __force __user *) &t);
 	set_fs (old_fs);
 	set_fs (old_fs);
 	if (put_compat_timespec(&t, interval))
 	if (put_compat_timespec(&t, interval))
 		return -EFAULT;
 		return -EFAULT;
@@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
 	}
 	}
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigprocmask(how,
 	ret = sys_rt_sigprocmask(how,
-				 set ? (sigset_t __user *) &s : NULL,
-				 oset ? (sigset_t __user *) &s : NULL,
+				 set ? (sigset_t __force __user *) &s : NULL,
+				 oset ? (sigset_t __force __user *) &s : NULL,
 				 sigsetsize);
 				 sigsetsize);
 	set_fs (old_fs);
 	set_fs (old_fs);
 	if (ret) return ret;
 	if (ret) return ret;
@@ -499,7 +506,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 	mm_segment_t old_fs = get_fs();
 	mm_segment_t old_fs = get_fs();
 		
 		
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
+	ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
 	set_fs (old_fs);
 	set_fs (old_fs);
 	if (!ret) {
 	if (!ret) {
 		switch (_NSIG_WORDS) {
 		switch (_NSIG_WORDS) {
@@ -524,7 +531,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
 	if (copy_siginfo_from_user32(&info, uinfo))
 	if (copy_siginfo_from_user32(&info, uinfo))
 		return -EFAULT;
 		return -EFAULT;
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
+	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
 	set_fs (old_fs);
 	set_fs (old_fs);
 	return ret;
 	return ret;
 }
 }
@@ -682,7 +689,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offse
 		
 		
 	set_fs(KERNEL_DS);
 	set_fs(KERNEL_DS);
 	ret = sys_sendfile(out_fd, in_fd,
 	ret = sys_sendfile(out_fd, in_fd,
-			   offset ? (off_t __user *) &of : NULL, count);
+			   offset ? (off_t __force __user *) &of : NULL, count);
 	set_fs(old_fs);
 	set_fs(old_fs);
 	
 	
 	if (offset && put_user(of, offset))
 	if (offset && put_user(of, offset))
@@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
 		
 		
 	set_fs(KERNEL_DS);
 	set_fs(KERNEL_DS);
 	ret = sys_sendfile64(out_fd, in_fd,
 	ret = sys_sendfile64(out_fd, in_fd,
-			     offset ? (loff_t __user *) &lof : NULL, count);
+			     offset ? (loff_t __force __user *) &lof : NULL,
+			     count);
 	set_fs(old_fs);
 	set_fs(old_fs);
 	
 	
 	if (offset && put_user(lof, offset))
 	if (offset && put_user(lof, offset))

+ 0 - 31
arch/s390/kernel/compat_linux.h

@@ -115,37 +115,6 @@ typedef struct
         __u32	addr;
         __u32	addr;
 } _psw_t32 __attribute__ ((aligned(8)));
 } _psw_t32 __attribute__ ((aligned(8)));
 
 
-#define PSW32_MASK_PER		0x40000000UL
-#define PSW32_MASK_DAT		0x04000000UL
-#define PSW32_MASK_IO		0x02000000UL
-#define PSW32_MASK_EXT		0x01000000UL
-#define PSW32_MASK_KEY		0x00F00000UL
-#define PSW32_MASK_MCHECK	0x00040000UL
-#define PSW32_MASK_WAIT		0x00020000UL
-#define PSW32_MASK_PSTATE	0x00010000UL
-#define PSW32_MASK_ASC		0x0000C000UL
-#define PSW32_MASK_CC		0x00003000UL
-#define PSW32_MASK_PM		0x00000f00UL
-
-#define PSW32_ADDR_AMODE31	0x80000000UL
-#define PSW32_ADDR_INSN		0x7FFFFFFFUL
-
-#define PSW32_BASE_BITS		0x00080000UL
-
-#define PSW32_ASC_PRIMARY	0x00000000UL
-#define PSW32_ASC_ACCREG	0x00004000UL
-#define PSW32_ASC_SECONDARY	0x00008000UL
-#define PSW32_ASC_HOME		0x0000C000UL
-
-#define PSW32_USER_BITS	(PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
-			 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
-			 PSW32_MASK_PSTATE)
-
-#define PSW32_MASK_MERGE(CURRENT,NEW) \
-        (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
-         ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
-
-
 typedef struct
 typedef struct
 {
 {
 	_psw_t32	psw;
 	_psw_t32	psw;

+ 4 - 4
arch/s390/kernel/compat_signal.c

@@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
 	}
 	}
 
 
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
-			     (stack_t __user *) (uoss ? &koss : NULL),
+	ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
+			     (stack_t __force __user *) (uoss ? &koss : NULL),
 			     regs->gprs[15]);
 			     regs->gprs[15]);
 	set_fs (old_fs);
 	set_fs (old_fs);
 
 
@@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
 	_s390_regs_common32 regs32;
 	_s390_regs_common32 regs32;
 	int err, i;
 	int err, i;
 
 
-	regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
+	regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
 					   (__u32)(regs->psw.mask >> 32));
 					   (__u32)(regs->psw.mask >> 32));
 	regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
 	regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
 	for (i = 0; i < NUM_GPRS; i++)
 	for (i = 0; i < NUM_GPRS; i++)
@@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 		goto badframe; 
 		goto badframe; 
 
 
 	set_fs (KERNEL_DS);
 	set_fs (KERNEL_DS);
-	do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
+	do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
 	set_fs (old_fs);
 	set_fs (old_fs);
 
 
 	return regs->gprs[2];
 	return regs->gprs[2];

+ 7 - 7
arch/s390/kernel/cpcmd.c

@@ -16,6 +16,7 @@
 #include <asm/ebcdic.h>
 #include <asm/ebcdic.h>
 #include <asm/cpcmd.h>
 #include <asm/cpcmd.h>
 #include <asm/system.h>
 #include <asm/system.h>
+#include <asm/io.h>
 
 
 static DEFINE_SPINLOCK(cpcmd_lock);
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
 static char cpcmd_buf[241];
@@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 	int len;
 	int len;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if ((rlen == 0) || (response == NULL)
-	    || !((unsigned long)response >> 31)) {
-		spin_lock_irqsave(&cpcmd_lock, flags);
-		len = __cpcmd(cmd, response, rlen, response_code);
-		spin_unlock_irqrestore(&cpcmd_lock, flags);
-	}
-	else {
+	if ((virt_to_phys(response) != (unsigned long) response) ||
+			(((unsigned long)response + rlen) >> 31)) {
 		lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
 		lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
 		if (!lowbuf) {
 		if (!lowbuf) {
 			printk(KERN_WARNING
 			printk(KERN_WARNING
@@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 		spin_unlock_irqrestore(&cpcmd_lock, flags);
 		spin_unlock_irqrestore(&cpcmd_lock, flags);
 		memcpy(response, lowbuf, rlen);
 		memcpy(response, lowbuf, rlen);
 		kfree(lowbuf);
 		kfree(lowbuf);
+	} else {
+		spin_lock_irqsave(&cpcmd_lock, flags);
+		len = __cpcmd(cmd, response, rlen, response_code);
+		spin_unlock_irqrestore(&cpcmd_lock, flags);
 	}
 	}
 	return len;
 	return len;
 }
 }

+ 1 - 0
arch/s390/kernel/crash.c

@@ -9,6 +9,7 @@
 
 
 #include <linux/threads.h>
 #include <linux/threads.h>
 #include <linux/kexec.h>
 #include <linux/kexec.h>
+#include <linux/reboot.h>
 
 
 void machine_crash_shutdown(struct pt_regs *regs)
 void machine_crash_shutdown(struct pt_regs *regs)
 {
 {

+ 8 - 10
arch/s390/kernel/debug.c

@@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = {
 	NULL
 	NULL
 };
 };
 
 
-struct debug_view debug_level_view = {
+static struct debug_view debug_level_view = {
 	"level",
 	"level",
 	&debug_prolog_level_fn,
 	&debug_prolog_level_fn,
 	NULL,
 	NULL,
@@ -129,7 +129,7 @@ struct debug_view debug_level_view = {
 	NULL
 	NULL
 };
 };
 
 
-struct debug_view debug_pages_view = {
+static struct debug_view debug_pages_view = {
 	"pages",
 	"pages",
 	&debug_prolog_pages_fn,
 	&debug_prolog_pages_fn,
 	NULL,
 	NULL,
@@ -138,7 +138,7 @@ struct debug_view debug_pages_view = {
 	NULL
 	NULL
 };
 };
 
 
-struct debug_view debug_flush_view = {
+static struct debug_view debug_flush_view = {
         "flush",
         "flush",
         NULL,
         NULL,
         NULL,
         NULL,
@@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = {
 	NULL
 	NULL
 };
 };
 
 
-
+/* used by dump analysis tools to determine version of debug feature */
 unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
 unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
 
 
 /* static globals */
 /* static globals */
 
 
 static debug_info_t *debug_area_first = NULL;
 static debug_info_t *debug_area_first = NULL;
 static debug_info_t *debug_area_last = NULL;
 static debug_info_t *debug_area_last = NULL;
-DECLARE_MUTEX(debug_lock);
+static DECLARE_MUTEX(debug_lock);
 
 
 static int initialized;
 static int initialized;
 
 
@@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = {
 	{ .ctl_name = 0 }
 	{ .ctl_name = 0 }
 };
 };
 
 
-struct ctl_table_header *s390dbf_sysctl_header;
+static struct ctl_table_header *s390dbf_sysctl_header;
 
 
 void
 void
 debug_stop_all(void)
 debug_stop_all(void)
@@ -1300,8 +1300,7 @@ out:
  * flushes debug areas
  * flushes debug areas
  */
  */
  
  
-void
-debug_flush(debug_info_t* id, int area)
+static void debug_flush(debug_info_t* id, int area)
 {
 {
         unsigned long flags;
         unsigned long flags;
         int i,j;
         int i,j;
@@ -1511,8 +1510,7 @@ out:
 /*
 /*
  * clean up module
  * clean up module
  */
  */
-void
-__exit debug_exit(void)
+static void __exit debug_exit(void)
 {
 {
 	debugfs_remove(debug_debugfs_root_entry);
 	debugfs_remove(debug_debugfs_root_entry);
 	unregister_sysctl_table(s390dbf_sysctl_header);
 	unregister_sysctl_table(s390dbf_sysctl_header);

+ 306 - 0
arch/s390/kernel/early.c

@@ -0,0 +1,306 @@
+/*
+ *  arch/s390/kernel/early.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
+ *		 Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/sclp.h>
+
+/*
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
+ */
+#define DEFSYS_CMD_SIZE		96
+#define SAVESYS_CMD_SIZE	32
+
+char kernel_nss_name[NSS_NAME_SIZE + 1];
+
+#ifdef CONFIG_SHARED_KERNEL
+static noinline __init void create_kernel_nss(void)
+{
+	unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned int sinitrd_pfn, einitrd_pfn;
+#endif
+	int response;
+	char *savesys_ptr;
+	char upper_command_line[COMMAND_LINE_SIZE];
+	char defsys_cmd[DEFSYS_CMD_SIZE];
+	char savesys_cmd[SAVESYS_CMD_SIZE];
+
+	/* Do nothing if we are not running under VM */
+	if (!MACHINE_IS_VM)
+		return;
+
+	/* Convert COMMAND_LINE to upper case */
+	for (i = 0; i < strlen(COMMAND_LINE); i++)
+		upper_command_line[i] = toupper(COMMAND_LINE[i]);
+
+	savesys_ptr = strstr(upper_command_line, "SAVESYS=");
+
+	if (!savesys_ptr)
+		return;
+
+	savesys_ptr += 8;    /* Point to the beginning of the NSS name */
+	for (i = 0; i < NSS_NAME_SIZE; i++) {
+		if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
+			break;
+		kernel_nss_name[i] = savesys_ptr[i];
+	}
+
+	stext_pfn = PFN_DOWN(__pa(&_stext));
+	eshared_pfn = PFN_DOWN(__pa(&_eshared));
+	end_pfn = PFN_UP(__pa(&_end));
+	min_size = end_pfn << 2;
+
+	sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+		kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
+		eshared_pfn, end_pfn);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (INITRD_START && INITRD_SIZE) {
+		sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
+		einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
+		min_size = einitrd_pfn << 2;
+		sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
+		sinitrd_pfn, einitrd_pfn);
+	}
+#endif
+
+	sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+	sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
+		kernel_nss_name, kernel_nss_name);
+
+	__cpcmd(defsys_cmd, NULL, 0, &response);
+
+	if (response != 0)
+		return;
+
+	__cpcmd(savesys_cmd, NULL, 0, &response);
+
+	if (response != strlen(savesys_cmd))
+		return;
+
+	ipl_flags = IPL_NSS_VALID;
+}
+
+#else /* CONFIG_SHARED_KERNEL */
+
+static inline void create_kernel_nss(void) { }
+
+#endif /* CONFIG_SHARED_KERNEL */
+
+/*
+ * Clear bss memory
+ */
+static noinline __init void clear_bss_section(void)
+{
+	memset(__bss_start, 0, _end - __bss_start);
+}
+
+/*
+ * Initialize storage key for kernel pages
+ */
+static noinline __init void init_kernel_storage_key(void)
+{
+	unsigned long end_pfn, init_pfn;
+
+	end_pfn = PFN_UP(__pa(&_end));
+
+	for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
+		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+}
+
+static noinline __init void detect_machine_type(void)
+{
+	struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+
+	asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
+
+	/* Running under z/VM ? */
+	if (cpuinfo->cpu_id.version == 0xff)
+		machine_flags |= 1;
+
+	/* Running on a P/390 ? */
+	if (cpuinfo->cpu_id.machine == 0x7490)
+		machine_flags |= 4;
+}
+
+static noinline __init int memory_fast_detect(void)
+{
+
+	unsigned long val0 = 0;
+	unsigned long val1 = 0xc;
+	int ret = -ENOSYS;
+
+	if (ipl_flags & IPL_NSS_VALID)
+		return -ENOSYS;
+
+	asm volatile(
+		"	diag	%1,%2,0x260\n"
+		"0:	lhi	%0,0\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
+
+	if (ret || val0 != val1)
+		return -ENOSYS;
+
+	memory_chunk[0].size = val0;
+	return 0;
+}
+
+#define ADDR2G	(1UL << 31)
+
+static noinline __init unsigned long sclp_memory_detect(void)
+{
+	struct sclp_readinfo_sccb *sccb;
+	unsigned long long memsize;
+
+	sccb = &s390_readinfo_sccb;
+
+	if (sccb->header.response_code != 0x10)
+		return 0;
+
+	if (sccb->rnsize)
+		memsize = sccb->rnsize << 20;
+	else
+		memsize = sccb->rnsize2 << 20;
+	if (sccb->rnmax)
+		memsize *= sccb->rnmax;
+	else
+		memsize *= sccb->rnmax2;
+#ifndef CONFIG_64BIT
+	/*
+	 * Can't deal with more than 2G in 31 bit addressing mode, so
+	 * limit the value in order to avoid strange side effects.
+	 */
+	if (memsize > ADDR2G)
+		memsize = ADDR2G;
+#endif
+	return (unsigned long) memsize;
+}
+
+static inline __init unsigned long __tprot(unsigned long addr)
+{
+	int cc = -1;
+
+	asm volatile(
+		"	tprot	0(%1),0\n"
+		"0:	ipm	%0\n"
+		"	srl	%0,28\n"
+		"1:\n"
+		EX_TABLE(0b,1b)
+		: "+d" (cc) : "a" (addr) : "cc");
+	return (unsigned long)cc;
+}
+
+/* Checking memory in 128KB increments. */
+#define CHUNK_INCR	(1UL << 17)
+
+static noinline __init void find_memory_chunks(unsigned long memsize)
+{
+	unsigned long addr = 0, old_addr = 0;
+	unsigned long old_cc = CHUNK_READ_WRITE;
+	unsigned long cc;
+	int chunk = 0;
+
+	while (chunk < MEMORY_CHUNKS) {
+		cc = __tprot(addr);
+		while (cc == old_cc) {
+			addr += CHUNK_INCR;
+			cc = __tprot(addr);
+#ifndef CONFIG_64BIT
+			if (addr == ADDR2G)
+				break;
+#endif
+		}
+
+		if (old_addr != addr &&
+		    (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
+			memory_chunk[chunk].addr = old_addr;
+			memory_chunk[chunk].size = addr - old_addr;
+			memory_chunk[chunk].type = old_cc;
+			chunk++;
+		}
+
+		old_addr = addr;
+		old_cc = cc;
+
+#ifndef CONFIG_64BIT
+		if (addr == ADDR2G)
+			break;
+#endif
+		/*
+		 * Finish memory detection at the first hole, unless
+		 * - we reached the hsa -> skip it.
+		 * - we know there must be more.
+		 */
+		if (cc == -1UL && !memsize && old_addr != ADDR2G)
+			break;
+		if (memsize && addr >= memsize)
+			break;
+	}
+}
+
+static __init void early_pgm_check_handler(void)
+{
+	unsigned long addr;
+	const struct exception_table_entry *fixup;
+
+	addr = S390_lowcore.program_old_psw.addr;
+	fixup = search_exception_tables(addr & PSW_ADDR_INSN);
+	if (!fixup)
+		disabled_wait(0);
+	S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+}
+
+static noinline __init void setup_lowcore_early(void)
+{
+	psw_t psw;
+
+	psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
+	S390_lowcore.external_new_psw = psw;
+	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+	S390_lowcore.program_new_psw = psw;
+	s390_base_pgm_handler_fn = early_pgm_check_handler;
+}
+
+/*
+ * Save ipl parameters, clear bss memory, initialize storage keys
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
+ */
+void __init startup_init(void)
+{
+	unsigned long memsize;
+
+	ipl_save_parameters();
+	clear_bss_section();
+	init_kernel_storage_key();
+	lockdep_init();
+	lockdep_off();
+	detect_machine_type();
+	create_kernel_nss();
+	sort_main_extable();
+	setup_lowcore_early();
+	sclp_readinfo_early();
+	memsize = sclp_memory_detect();
+	if (memory_fast_detect() < 0)
+		find_memory_chunks(memsize);
+	lockdep_on();
+}

+ 1 - 0
arch/s390/kernel/ebcdic.c

@@ -11,6 +11,7 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <asm/types.h>
 #include <asm/types.h>
+#include <asm/ebcdic.h>
 
 
 /*
 /*
  * ASCII (IBM PC 437)  -> EBCDIC 037
  * ASCII (IBM PC 437)  -> EBCDIC 037

+ 7 - 187
arch/s390/kernel/head31.S

@@ -51,175 +51,14 @@ startup_continue:
 	st	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	st	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	ahi	%r15,-96
 	ahi	%r15,-96
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-	l	%r14,.Lipl_save_parameters-.LPG1(%r13)
-	basr	%r14,%r14
 #
 #
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
 #
 #
-	l	%r2,.Lbss_bgn-.LPG1(%r13) # start of bss
-	l	%r3,.Lbss_end-.LPG1(%r13) # end of bss
-	sr	%r3,%r2			# length of bss
-	sr	%r4,%r4
-	sr	%r5,%r5			# set src,length and pad to zero
-	sr	%r0,%r0
-	mvcle	%r2,%r4,0		# clear mem
-	jo	.-4			# branch back, if not finish
-
-	l	%r2,.Lrcp-.LPG1(%r13)	# Read SCP forced command word
-.Lservicecall:
-	stosm	.Lpmask-.LPG1(%r13),0x01	# authorize ext interrupts
-
-	stctl	%r0, %r0,.Lcr-.LPG1(%r13)	# get cr0
-	la	%r1,0x200		# set bit 22
-	o	%r1,.Lcr-.LPG1(%r13)	# or old cr0 with r1
-	st	%r1,.Lcr-.LPG1(%r13)
-	lctl	%r0, %r0,.Lcr-.LPG1(%r13)	# load modified cr0
-
-	mvc	__LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
-	la	%r1, .Lsclph-.LPG1(%r13)
-	a	%r1,__LC_EXT_NEW_PSW+4	# set handler
-	st	%r1,__LC_EXT_NEW_PSW+4
-
-	l	%r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
-	lr	%r1,%r4			# our sccb
-	.insn	rre,0xb2200000,%r2,%r1	# service call
-	ipm	%r1
-	srl	%r1,28			# get cc code
-	xr	%r3, %r3
-	chi	%r1,3
-	be	.Lfchunk-.LPG1(%r13)	# leave
-	chi	%r1,2
-	be	.Lservicecall-.LPG1(%r13)
-	lpsw	.Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-	lh	%r1,.Lsccbr-.Lsccb(%r4)
-	chi	%r1,0x10		# 0x0010 is the sucess code
-	je	.Lprocsccb		# let's process the sccb
-	chi	%r1,0x1f0
-	bne	.Lfchunk-.LPG1(%r13)	# unhandled error code
-	c	%r2, .Lrcp-.LPG1(%r13)	# Did we try Read SCP forced
-	bne	.Lfchunk-.LPG1(%r13)	# if no, give up
-	l	%r2, .Lrcp2-.LPG1(%r13)	# try with Read SCP
-	b	.Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-	lhi	%r1,0
-	icm	%r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
-	jnz	.Lscnd
-	lhi	%r1,0x800		# otherwise report 2GB
-.Lscnd:
-	lhi	%r3,0x800		# limit reported memory size to 2GB
-	cr	%r1,%r3
-	jl	.Lno2gb
-	lr	%r1,%r3
-.Lno2gb:
-	xr	%r3,%r3			# same logic
-	ic	%r3,.Lscpa1-.Lsccb(%r4)
-	chi	%r3,0x00
-	jne	.Lcompmem
-	l	%r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-	mr	%r2,%r1			# mem in MB on 128-bit
-	l	%r1,.Lonemb-.LPG1(%r13)
-	mr	%r2,%r1			# mem size in bytes in %r3
-	b	.Lfchunk-.LPG1(%r13)
-
-	.align 4
-.Lipl_save_parameters:
-	.long	ipl_save_parameters
-.Linittu:
-	.long	init_thread_union
-.Lpmask:
-	.byte	0
-	.align	8
-.Lpcext:.long	0x00080000,0x80000000
-.Lcr:
-	.long	0x00			# place holder for cr0
-	.align	8
-.Lwaitsclp:
-	.long 0x010a0000,0x80000000 + .Lsclph
-.Lrcp:
-	.int	0x00120001		# Read SCP forced code
-.Lrcp2:
-	.int	0x00020001		# Read SCP code
-.Lonemb:
-	.int	0x100000
-.Lfchunk:
+	l	%r14,.Lstartup_init-.LPG1(%r13)
+	basr	%r14,%r14
 
 
-#
-# find memory chunks.
-#
-	lr	%r9,%r3			# end of mem
-	mvc	__LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
-	la	%r1,1			# test in increments of 128KB
-	sll	%r1,17
-	l	%r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
-	slr	%r4,%r4			# set start of chunk to zero
-	slr	%r5,%r5			# set end of chunk to zero
-	slr	%r6,%r6			# set access code to zero
-	la	%r10,MEMORY_CHUNKS	# number of chunks
-.Lloop:
-	tprot	0(%r5),0		# test protection of first byte
-	ipm	%r7
-	srl	%r7,28
-	clr	%r6,%r7			# compare cc with last access code
-	be	.Lsame-.LPG1(%r13)
-	lhi	%r8,0			# no program checks
-	b	.Lsavchk-.LPG1(%r13)
-.Lsame:
-	ar	%r5,%r1			# add 128KB to end of chunk
-	bno	.Lloop-.LPG1(%r13)	# r1 < 0x80000000 -> loop
-.Lchkmem:				# > 2GB or tprot got a program check
-	lhi	%r8,1			# set program check flag
-.Lsavchk:
-	clr	%r4,%r5			# chunk size > 0?
-	be	.Lchkloop-.LPG1(%r13)
-	st	%r4,0(%r3)		# store start address of chunk
-	lr	%r0,%r5
-	slr	%r0,%r4
-	st	%r0,4(%r3)		# store size of chunk
-	st	%r6,8(%r3)		# store type of chunk
-	la	%r3,12(%r3)
-	ahi	%r10,-1			# update chunk number
-.Lchkloop:
-	lr	%r6,%r7			# set access code to last cc
-	# we got an exception or we're starting a new
-	# chunk , we must check if we should
-	# still try to find valid memory (if we detected
-	# the amount of available storage), and if we
-	# have chunks left
-	xr	%r0,%r0
-	clr	%r0,%r9			# did we detect memory?
-	je	.Ldonemem		# if not, leave
-	chi	%r10,0			# do we have chunks left?
-	je	.Ldonemem
-	chi	%r8,1			# program check ?
-	je	.Lpgmchk
-	lr	%r4,%r5			# potential new chunk
-	alr	%r5,%r1			# add 128KB to end of chunk
-	j	.Llpcnt
-.Lpgmchk:
-	alr	%r5,%r1			# add 128KB to end of chunk
-	lr	%r4,%r5			# potential new chunk
-.Llpcnt:
-	clr	%r5,%r9			# should we go on?
-	jl	.Lloop
-.Ldonemem:
 	l	%r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
 	l	%r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
-#
-# find out if we are running under VM
-#
-	stidp	__LC_CPUID		# store cpuid
-	tm	__LC_CPUID,0xff		# running under VM ?
-	bno	.Lnovm-.LPG1(%r13)
-	oi	3(%r12),1		# set VM flag
-.Lnovm:
-	lh	%r0,__LC_CPUID+4	# get cpu version
-	chi	%r0,0x7490		# running on a P/390 ?
-	bne	.Lnop390-.LPG1(%r13)
-	oi	3(%r12),4		# set P/390 flag
-.Lnop390:
-
 #
 #
 # find out if we have an IEEE fpu
 # find out if we have an IEEE fpu
 #
 #
@@ -295,7 +134,6 @@ startup_continue:
 	.long	0			# cr15: linkage stack operations
 	.long	0			# cr15: linkage stack operations
 .Lduct:	.long	0,0,0,0,0,0,0,0
 .Lduct:	.long	0,0,0,0,0,0,0,0
 	.long	0,0,0,0,0,0,0,0
 	.long	0,0,0,0,0,0,0,0
-.Lpcmem:.long	0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long	0x00080000,0x80000000 + .Lchkfpu
 .Lpcfpu:.long	0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long	0x00080000,0x80000000 + .Lchkcsp
 .Lpccsp:.long	0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long	0x00080000,0x80000000 + .Lchkmvpg
 .Lpcmvpg:.long	0x00080000,0x80000000 + .Lchkmvpg
@@ -306,7 +144,9 @@ startup_continue:
 .Lbss_bgn:  .long __bss_start
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
 .Lbss_end:  .long _end
 .Lparmaddr: .long PARMAREA
 .Lparmaddr: .long PARMAREA
-.Lsccbaddr: .long .Lsccb
+.Linittu:   .long init_thread_union
+.Lstartup_init:
+	    .long startup_init
 
 
 	.globl ipl_schib
 	.globl ipl_schib
 ipl_schib:
 ipl_schib:
@@ -322,26 +162,6 @@ ipl_devno:
 	.word 0
 	.word 0
 
 
 	.org	0x12000
 	.org	0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-	.hword	0x1000			# length, one page
-	.byte	0x00,0x00,0x00
-	.byte	0x80			# variable response bit set
-.Lsccbr:
-	.hword	0x00			# response code
-.Lscpincr1:
-	.hword	0x00
-.Lscpa1:
-	.byte	0x00
-	.fill	89,1,0
-.Lscpa2:
-	.int	0x00
-.Lscpincr2:
-	.quad	0x00
-	.fill	3984,1,0
-	.org	0x13000
-
 #ifdef CONFIG_SHARED_KERNEL
 #ifdef CONFIG_SHARED_KERNEL
 	.org	0x100000
 	.org	0x100000
 #endif
 #endif

+ 3 - 190
arch/s390/kernel/head64.S

@@ -58,182 +58,14 @@ startup_continue:
 	stg	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	stg	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	aghi	%r15,-160
 	aghi	%r15,-160
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-	brasl	%r14,ipl_save_parameters
 #
 #
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
 #
 #
-	larl	%r2,__bss_start 	# start of bss segment
-	larl	%r3,_end		# end of bss segment
-	sgr	%r3,%r2 		# length of bss
-	sgr	%r4,%r4 		#
-	sgr	%r5,%r5 		# set src,length and pad to zero
-	mvcle	%r2,%r4,0		# clear mem
-	jo	.-4			# branch back, if not finish
+	brasl	%r14,startup_init
 					# set program check new psw mask
 					# set program check new psw mask
 	mvc	__LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
 	mvc	__LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
-	larl	%r1,.Lslowmemdetect	# set program check address
-	stg	%r1,__LC_PGM_NEW_PSW+8
-	lghi	%r1,0xc
-	diag	%r0,%r1,0x260		# get memory size of virtual machine
-	cgr	%r0,%r1			# different? -> old detection routine
-	jne	.Lslowmemdetect
-	aghi	%r1,1			# size is one more than end
-	larl	%r2,memory_chunk
-	stg	%r1,8(%r2)		# store size of chunk
-	j	.Ldonemem
-
-.Lslowmemdetect:
-	l	%r2,.Lrcp-.LPG1(%r13)	# Read SCP forced command word
-.Lservicecall:
-	stosm	.Lpmask-.LPG1(%r13),0x01	# authorize ext interrupts
-
-	stctg	%r0,%r0,.Lcr-.LPG1(%r13)	# get cr0
-	la	%r1,0x200		# set bit 22
-	og	%r1,.Lcr-.LPG1(%r13)	# or old cr0 with r1
-	stg	%r1,.Lcr-.LPG1(%r13)
-	lctlg	%r0,%r0,.Lcr-.LPG1(%r13)	# load modified cr0
-
-	mvc	__LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
-	larl	%r1,.Lsclph
-	stg	%r1,__LC_EXT_NEW_PSW+8	# set handler
-
-	larl	%r4,.Lsccb		# %r4 is our index for sccb stuff
-	lgr	%r1,%r4			# our sccb
-	.insn	rre,0xb2200000,%r2,%r1	# service call
-	ipm	%r1
-	srl	%r1,28			# get cc code
-	xr	%r3,%r3
-	chi	%r1,3
-	be	.Lfchunk-.LPG1(%r13)	# leave
-	chi	%r1,2
-	be	.Lservicecall-.LPG1(%r13)
-	lpswe	.Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-	lh	%r1,.Lsccbr-.Lsccb(%r4)
-	chi	%r1,0x10		# 0x0010 is the sucess code
-	je	.Lprocsccb		# let's process the sccb
-	chi	%r1,0x1f0
-	bne	.Lfchunk-.LPG1(%r13)	# unhandled error code
-	c	%r2,.Lrcp-.LPG1(%r13)	# Did we try Read SCP forced
-	bne	.Lfchunk-.LPG1(%r13)	# if no, give up
-	l	%r2,.Lrcp2-.LPG1(%r13)	# try with Read SCP
-	b	.Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-	lghi	%r1,0
-	icm	%r1,3,.Lscpincr1-.Lsccb(%r4)	# use this one if != 0
-	jnz	.Lscnd
-	lg	%r1,.Lscpincr2-.Lsccb(%r4)	# otherwise use this one
-.Lscnd:
-	xr	%r3,%r3			# same logic
-	ic	%r3,.Lscpa1-.Lsccb(%r4)
-	chi	%r3,0x00
-	jne	.Lcompmem
-	l	%r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-	mlgr	%r2,%r1			# mem in MB on 128-bit
-	l	%r1,.Lonemb-.LPG1(%r13)
-	mlgr	%r2,%r1			# mem size in bytes in %r3
-	b	.Lfchunk-.LPG1(%r13)
-
-	.align	4
-.Lpmask:
-	.byte	0
-	.align	8
-.Lcr:
-	.quad	0x00  # place holder for cr0
-.Lwaitsclp:
-	.quad	0x0102000180000000,.Lsclph
-.Lrcp:
-	.int	0x00120001 # Read SCP forced code
-.Lrcp2:
-	.int	0x00020001 # Read SCP code
-.Lonemb:
-	.int	0x100000
-
-.Lfchunk:
-
-#
-# find memory chunks.
-#
-	lgr	%r9,%r3			# end of mem
-	larl	%r1,.Lchkmem		# set program check address
-	stg	%r1,__LC_PGM_NEW_PSW+8
-	la	%r1,1			# test in increments of 128KB
-	sllg	%r1,%r1,17
-	larl	%r3,memory_chunk
-	slgr	%r4,%r4 		# set start of chunk to zero
-	slgr	%r5,%r5 		# set end of chunk to zero
-	slr	%r6,%r6			# set access code to zero
-	la	%r10,MEMORY_CHUNKS	# number of chunks
-.Lloop:
-	tprot	0(%r5),0		# test protection of first byte
-	ipm	%r7
-	srl	%r7,28
-	clr	%r6,%r7			# compare cc with last access code
-	je	.Lsame
-	lghi	%r8,0			# no program checks
-	j	.Lsavchk
-.Lsame:
-	algr	%r5,%r1			# add 128KB to end of chunk
-					# no need to check here,
-	brc	12,.Lloop		# this is the same chunk
-.Lchkmem:				# > 16EB or tprot got a program check
-	lghi	%r8,1			# set program check flag
-.Lsavchk:
-	clgr	%r4,%r5			# chunk size > 0?
-	je	.Lchkloop
-	stg	%r4,0(%r3)		# store start address of chunk
-	lgr	%r0,%r5
-	slgr	%r0,%r4
-	stg	%r0,8(%r3)		# store size of chunk
-	st	%r6,20(%r3)		# store type of chunk
-	la	%r3,24(%r3)
-	ahi	%r10,-1			# update chunk number
-.Lchkloop:
-	lr	%r6,%r7			# set access code to last cc
-	# we got an exception or we're starting a new
-	# chunk , we must check if we should
-	# still try to find valid memory (if we detected
-	# the amount of available storage), and if we
-	# have chunks left
-	lghi	%r4,1
-	sllg	%r4,%r4,31
-	clgr	%r5,%r4
-	je	.Lhsaskip
-	xr	%r0, %r0
-	clgr	%r0, %r9		# did we detect memory?
-	je	.Ldonemem		# if not, leave
-	chi	%r10, 0			# do we have chunks left?
-	je	.Ldonemem
-.Lhsaskip:
-	chi	%r8,1			# program check ?
-	je	.Lpgmchk
-	lgr	%r4,%r5			# potential new chunk
-	algr	%r5,%r1			# add 128KB to end of chunk
-	j	.Llpcnt
-.Lpgmchk:
-	algr	%r5,%r1			# add 128KB to end of chunk
-	lgr	%r4,%r5			# potential new chunk
-.Llpcnt:
-	clgr	%r5,%r9			# should we go on?
-	jl	.Lloop
-.Ldonemem:
-
 	larl	%r12,machine_flags
 	larl	%r12,machine_flags
-#
-# find out if we are running under VM
-#
-	stidp	__LC_CPUID		# store cpuid
-	tm	__LC_CPUID,0xff 	# running under VM ?
-	bno	0f-.LPG1(%r13)
-	oi	7(%r12),1		# set VM flag
-0:	lh	%r0,__LC_CPUID+4	# get cpu version
-	chi	%r0,0x7490		# running on a P/390 ?
-	bne	1f-.LPG1(%r13)
-	oi	7(%r12),4		# set P/390 flag
-1:
-
 #
 #
 # find out if we have the MVPG instruction
 # find out if we have the MVPG instruction
 #
 #
@@ -336,25 +168,6 @@ ipl_devno:
 	.word 0
 	.word 0
 
 
 	.org	0x12000
 	.org	0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-	.hword	0x1000			# length, one page
-	.byte	0x00,0x00,0x00
-	.byte	0x80			# variable response bit set
-.Lsccbr:
-	.hword	0x00			# response code
-.Lscpincr1:
-	.hword	0x00
-.Lscpa1:
-	.byte	0x00
-	.fill	89,1,0
-.Lscpa2:
-	.int	0x00
-.Lscpincr2:
-	.quad	0x00
-	.fill	3984,1,0
-	.org	0x13000
 
 
 #ifdef CONFIG_SHARED_KERNEL
 #ifdef CONFIG_SHARED_KERNEL
 	.org	0x100000
 	.org	0x100000

+ 95 - 11
arch/s390/kernel/ipl.c

@@ -20,26 +20,27 @@
 #include <asm/cio.h>
 #include <asm/cio.h>
 #include <asm/ebcdic.h>
 #include <asm/ebcdic.h>
 #include <asm/reset.h>
 #include <asm/reset.h>
+#include <asm/sclp.h>
 
 
 #define IPL_PARM_BLOCK_VERSION 0
 #define IPL_PARM_BLOCK_VERSION 0
-#define LOADPARM_LEN 8
 
 
-extern char s390_readinfo_sccb[];
-#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
-#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
-#define SCCB_FLAG (s390_readinfo_sccb[91])
+#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
+#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
+#define SCCB_FLAG (s390_readinfo_sccb.flags)
 
 
 enum ipl_type {
 enum ipl_type {
 	IPL_TYPE_NONE	 = 1,
 	IPL_TYPE_NONE	 = 1,
 	IPL_TYPE_UNKNOWN = 2,
 	IPL_TYPE_UNKNOWN = 2,
 	IPL_TYPE_CCW	 = 4,
 	IPL_TYPE_CCW	 = 4,
 	IPL_TYPE_FCP	 = 8,
 	IPL_TYPE_FCP	 = 8,
+	IPL_TYPE_NSS	 = 16,
 };
 };
 
 
 #define IPL_NONE_STR	 "none"
 #define IPL_NONE_STR	 "none"
 #define IPL_UNKNOWN_STR  "unknown"
 #define IPL_UNKNOWN_STR  "unknown"
 #define IPL_CCW_STR	 "ccw"
 #define IPL_CCW_STR	 "ccw"
 #define IPL_FCP_STR	 "fcp"
 #define IPL_FCP_STR	 "fcp"
+#define IPL_NSS_STR	 "nss"
 
 
 static char *ipl_type_str(enum ipl_type type)
 static char *ipl_type_str(enum ipl_type type)
 {
 {
@@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type type)
 		return IPL_CCW_STR;
 		return IPL_CCW_STR;
 	case IPL_TYPE_FCP:
 	case IPL_TYPE_FCP:
 		return IPL_FCP_STR;
 		return IPL_FCP_STR;
+	case IPL_TYPE_NSS:
+		return IPL_NSS_STR;
 	case IPL_TYPE_UNKNOWN:
 	case IPL_TYPE_UNKNOWN:
 	default:
 	default:
 		return IPL_UNKNOWN_STR;
 		return IPL_UNKNOWN_STR;
@@ -64,6 +67,7 @@ enum ipl_method {
 	IPL_METHOD_FCP_RO_DIAG,
 	IPL_METHOD_FCP_RO_DIAG,
 	IPL_METHOD_FCP_RW_DIAG,
 	IPL_METHOD_FCP_RW_DIAG,
 	IPL_METHOD_FCP_RO_VM,
 	IPL_METHOD_FCP_RO_VM,
+	IPL_METHOD_NSS,
 };
 };
 
 
 enum shutdown_action {
 enum shutdown_action {
@@ -114,11 +118,14 @@ enum diag308_rc {
 static int diag308_set_works = 0;
 static int diag308_set_works = 0;
 
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static enum ipl_method reipl_method = IPL_METHOD_NONE;
 static enum ipl_method reipl_method = IPL_METHOD_NONE;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
 static struct ipl_parameter_block *reipl_block_ccw;
 
 
+static char reipl_nss_name[NSS_NAME_SIZE + 1];
+
 static int dump_capabilities = IPL_TYPE_NONE;
 static int dump_capabilities = IPL_TYPE_NONE;
 static enum ipl_type dump_type = IPL_TYPE_NONE;
 static enum ipl_type dump_type = IPL_TYPE_NONE;
 static enum ipl_method dump_method = IPL_METHOD_NONE;
 static enum ipl_method dump_method = IPL_METHOD_NONE;
@@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
 			sys_##_prefix##_##_name##_show,			\
 			sys_##_prefix##_##_name##_show,			\
 			sys_##_prefix##_##_name##_store);
 			sys_##_prefix##_##_name##_store);
 
 
+#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys,	\
+		char *page)						\
+{									\
+	return sprintf(page, _fmt_out, _value);				\
+}									\
+static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+		const char *buf, size_t len)				\
+{									\
+	if (sscanf(buf, _fmt_in, _value) != 1)				\
+		return -EINVAL;						\
+	return len;							\
+}									\
+static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\
+	__ATTR(_name,(S_IRUGO | S_IWUSR),				\
+			sys_##_prefix##_##_name##_show,			\
+			sys_##_prefix##_##_name##_store);
+
 static void make_attrs_ro(struct attribute **attrs)
 static void make_attrs_ro(struct attribute **attrs)
 {
 {
 	while (*attrs) {
 	while (*attrs) {
@@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void)
 {
 {
 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
 
+	if (ipl_flags & IPL_NSS_VALID)
+		return IPL_TYPE_NSS;
 	if (!(ipl_flags & IPL_DEVNO_VALID))
 	if (!(ipl_flags & IPL_DEVNO_VALID))
 		return IPL_TYPE_UNKNOWN;
 		return IPL_TYPE_UNKNOWN;
 	if (!(ipl_flags & IPL_PARMBLOCK_VALID))
 	if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = {
 	.attrs = ipl_ccw_attrs,
 	.attrs = ipl_ccw_attrs,
 };
 };
 
 
+/* NSS ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
+
+static struct attribute *ipl_nss_attrs[] = {
+	&sys_ipl_type_attr.attr,
+	&sys_ipl_nss_name_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ipl_nss_attr_group = {
+	.attrs = ipl_nss_attrs,
+};
+
 /* UNKNOWN ipl device attributes */
 /* UNKNOWN ipl device attributes */
 
 
 static struct attribute *ipl_unknown_attrs[] = {
 static struct attribute *ipl_unknown_attrs[] = {
@@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = {
 	.attrs = reipl_ccw_attrs,
 	.attrs = reipl_ccw_attrs,
 };
 };
 
 
+
+/* NSS reipl device attributes */
+
+DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+
+static struct attribute *reipl_nss_attrs[] = {
+	&sys_reipl_nss_name_attr.attr,
+	NULL,
+};
+
+static struct attribute_group reipl_nss_attr_group = {
+	.name  = IPL_NSS_STR,
+	.attrs = reipl_nss_attrs,
+};
+
 /* reipl type */
 /* reipl type */
 
 
 static int reipl_set_type(enum ipl_type type)
 static int reipl_set_type(enum ipl_type type)
@@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type)
 		else
 		else
 			reipl_method = IPL_METHOD_FCP_RO_DIAG;
 			reipl_method = IPL_METHOD_FCP_RO_DIAG;
 		break;
 		break;
+	case IPL_TYPE_NSS:
+		reipl_method = IPL_METHOD_NSS;
+		break;
 	default:
 	default:
 		reipl_method = IPL_METHOD_NONE;
 		reipl_method = IPL_METHOD_NONE;
 	}
 	}
@@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
 		rc = reipl_set_type(IPL_TYPE_CCW);
 		rc = reipl_set_type(IPL_TYPE_CCW);
 	else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
 	else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
 		rc = reipl_set_type(IPL_TYPE_FCP);
 		rc = reipl_set_type(IPL_TYPE_FCP);
+	else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
+		rc = reipl_set_type(IPL_TYPE_NSS);
 	return (rc != 0) ? rc : len;
 	return (rc != 0) ? rc : len;
 }
 }
 
 
@@ -647,6 +708,10 @@ void do_reipl(void)
 	case IPL_METHOD_FCP_RO_VM:
 	case IPL_METHOD_FCP_RO_VM:
 		__cpcmd("IPL", NULL, 0, NULL);
 		__cpcmd("IPL", NULL, 0, NULL);
 		break;
 		break;
+	case IPL_METHOD_NSS:
+		sprintf(buf, "IPL %s", reipl_nss_name);
+		__cpcmd(buf, NULL, 0, NULL);
+		break;
 	case IPL_METHOD_NONE:
 	case IPL_METHOD_NONE:
 	default:
 	default:
 		if (MACHINE_IS_VM)
 		if (MACHINE_IS_VM)
@@ -733,6 +798,10 @@ static int __init ipl_init(void)
 	case IPL_TYPE_FCP:
 	case IPL_TYPE_FCP:
 		rc = ipl_register_fcp_files();
 		rc = ipl_register_fcp_files();
 		break;
 		break;
+	case IPL_TYPE_NSS:
+		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+					&ipl_nss_attr_group);
+		break;
 	default:
 	default:
 		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
 		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
 					&ipl_unknown_attr_group);
 					&ipl_unknown_attr_group);
@@ -755,6 +824,20 @@ static void __init reipl_probe(void)
 	free_page((unsigned long)buffer);
 	free_page((unsigned long)buffer);
 }
 }
 
 
+static int __init reipl_nss_init(void)
+{
+	int rc;
+
+	if (!MACHINE_IS_VM)
+		return 0;
+	rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+	if (rc)
+		return rc;
+	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+	reipl_capabilities |= IPL_TYPE_NSS;
+	return 0;
+}
+
 static int __init reipl_ccw_init(void)
 static int __init reipl_ccw_init(void)
 {
 {
 	int rc;
 	int rc;
@@ -835,6 +918,9 @@ static int __init reipl_init(void)
 	if (rc)
 	if (rc)
 		return rc;
 		return rc;
 	rc = reipl_fcp_init();
 	rc = reipl_fcp_init();
+	if (rc)
+		return rc;
+	rc = reipl_nss_init();
 	if (rc)
 	if (rc)
 		return rc;
 		return rc;
 	rc = reipl_set_type(ipl_get_type());
 	rc = reipl_set_type(ipl_get_type());
@@ -993,8 +1079,6 @@ static void do_reset_calls(void)
 		reset->fn();
 		reset->fn();
 }
 }
 
 
-extern void reset_mcck_handler(void);
-extern void reset_pgm_handler(void);
 extern __u32 dump_prefix_page;
 extern __u32 dump_prefix_page;
 
 
 void s390_reset_system(void)
 void s390_reset_system(void)
@@ -1016,14 +1100,14 @@ void s390_reset_system(void)
 	__ctl_clear_bit(0,28);
 	__ctl_clear_bit(0,28);
 
 
 	/* Set new machine check handler */
 	/* Set new machine check handler */
-	S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+	S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
 	S390_lowcore.mcck_new_psw.addr =
 	S390_lowcore.mcck_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
+		PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
 
 
 	/* Set new program check handler */
 	/* Set new program check handler */
-	S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+	S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
 	S390_lowcore.program_new_psw.addr =
 	S390_lowcore.program_new_psw.addr =
-		PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
+		PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
 
 	do_reset_calls();
 	do_reset_calls();
 }
 }

+ 12 - 3
arch/s390/kernel/irq.c

@@ -1,9 +1,9 @@
 /*
 /*
  *  arch/s390/kernel/irq.c
  *  arch/s390/kernel/irq.c
  *
  *
- *  S390 version
- *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2004,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *		 Thomas Spatzier (tspat@de.ibm.com)
  *
  *
  * This file contains interrupt related functions.
  * This file contains interrupt related functions.
  */
  */
@@ -14,6 +14,8 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/cpu.h>
 #include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/profile.h>
 
 
 /*
 /*
  * show_interrupts is needed by /proc/interrupts.
  * show_interrupts is needed by /proc/interrupts.
@@ -93,5 +95,12 @@ asmlinkage void do_softirq(void)
 
 
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
-
 EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(do_softirq);
+
+void init_irq_proc(void)
+{
+	struct proc_dir_entry *root_irq_dir;
+
+	root_irq_dir = proc_mkdir("irq", NULL);
+	create_prof_cpu_mask(root_irq_dir);
+}

+ 26 - 6
arch/s390/kernel/kprobes.c

@@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
 static int __kprobes swap_instruction(void *aref)
 static int __kprobes swap_instruction(void *aref)
 {
 {
 	struct ins_replace_args *args = aref;
 	struct ins_replace_args *args = aref;
+	u32 *addr;
+	u32 instr;
 	int err = -EFAULT;
 	int err = -EFAULT;
 
 
+	/*
+	 * Text segment is read-only, hence we use stura to bypass dynamic
+	 * address translation to exchange the instruction. Since stura
+	 * always operates on four bytes, but we only want to exchange two
+	 * bytes do some calculations to get things right. In addition we
+	 * shall not cross any page boundaries (vmalloc area!) when writing
+	 * the new instruction.
+	 */
+	addr = (u32 *)ALIGN((unsigned long)args->ptr, 4);
+	if ((unsigned long)args->ptr & 2)
+		instr = ((*addr) & 0xffff0000) | args->new;
+	else
+		instr = ((*addr) & 0x0000ffff) | args->new << 16;
+
 	asm volatile(
 	asm volatile(
-		"0: mvc  0(2,%2),0(%3)\n"
-		"1: la   %0,0\n"
+		"	lra	%1,0(%1)\n"
+		"0:	stura	%2,%1\n"
+		"1:	la	%0,0\n"
 		"2:\n"
 		"2:\n"
 		EX_TABLE(0b,2b)
 		EX_TABLE(0b,2b)
-		: "+d" (err), "=m" (*args->ptr)
-		: "a" (args->ptr), "a" (&args->new), "m" (args->new));
+		: "+d" (err)
+		: "a" (addr), "d" (instr)
+		: "memory", "cc");
+
 	return err;
 	return err;
 }
 }
 
 
@@ -356,7 +375,7 @@ no_kprobe:
  *	- When the probed function returns, this probe
  *	- When the probed function returns, this probe
  *		causes the handlers to fire
  *		causes the handlers to fire
  */
  */
-void __kprobes kretprobe_trampoline_holder(void)
+void kretprobe_trampoline_holder(void)
 {
 {
 	asm volatile(".global kretprobe_trampoline\n"
 	asm volatile(".global kretprobe_trampoline\n"
 		     "kretprobe_trampoline: bcr 0,0\n");
 		     "kretprobe_trampoline: bcr 0,0\n");
@@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_holder(void)
 /*
 /*
  * Called when the probe at kretprobe trampoline is hit
  * Called when the probe at kretprobe trampoline is hit
  */
  */
-int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+					      struct pt_regs *regs)
 {
 {
 	struct kretprobe_instance *ri = NULL;
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
 	struct hlist_head *head, empty_rp;

+ 1 - 0
arch/s390/kernel/machine_kexec.c

@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
+#include <linux/reboot.h>
 #include <asm/cio.h>
 #include <asm/cio.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable.h>

+ 3 - 2
arch/s390/kernel/module.c

@@ -30,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/moduleloader.h>
 
 
 #if 0
 #if 0
 #define DEBUGP printk
 #define DEBUGP printk
@@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region)
            table entries. */
            table entries. */
 }
 }
 
 
-static inline void
+static void
 check_rela(Elf_Rela *rela, struct module *me)
 check_rela(Elf_Rela *rela, struct module *me)
 {
 {
 	struct mod_arch_syminfo *info;
 	struct mod_arch_syminfo *info;
@@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 	return -ENOEXEC;
 	return -ENOEXEC;
 }
 }
 
 
-static inline int
+static int
 apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 
 apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 
 	   struct module *me)
 	   struct module *me)
 {
 {

+ 2 - 2
arch/s390/kernel/process.c

@@ -144,7 +144,7 @@ static void default_idle(void)
 
 
 	trace_hardirqs_on();
 	trace_hardirqs_on();
 	/* Wait for external, I/O or machine check interrupt. */
 	/* Wait for external, I/O or machine check interrupt. */
-	__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+	__load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
 			PSW_MASK_IO | PSW_MASK_EXT);
 			PSW_MASK_IO | PSW_MASK_EXT);
 }
 }
 
 
@@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 	struct pt_regs regs;
 	struct pt_regs regs;
 
 
 	memset(&regs, 0, sizeof(regs));
 	memset(&regs, 0, sizeof(regs));
-	regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
 	regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
 	regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
 	regs.gprs[9] = (unsigned long) fn;
 	regs.gprs[9] = (unsigned long) fn;
 	regs.gprs[10] = (unsigned long) arg;
 	regs.gprs[10] = (unsigned long) arg;

+ 0 - 20
arch/s390/kernel/profile.c

@@ -1,20 +0,0 @@
-/*
- * arch/s390/kernel/profile.c
- *
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- */
-#include <linux/proc_fs.h>
-#include <linux/profile.h>
-
-static struct proc_dir_entry * root_irq_dir;
-
-void init_irq_proc(void)
-{
-	/* create /proc/irq */
-	root_irq_dir = proc_mkdir("irq", NULL);
-
-	/* create /proc/irq/prof_cpu_mask */
-	create_prof_cpu_mask(root_irq_dir);
-}

+ 24 - 22
arch/s390/kernel/ptrace.c

@@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }
 }
 
 
-void
-set_single_step(struct task_struct *task)
+static void set_single_step(struct task_struct *task)
 {
 {
 	task->thread.per_info.single_step = 1;
 	task->thread.per_info.single_step = 1;
 	FixPerRegisters(task);
 	FixPerRegisters(task);
 }
 }
 
 
-void
-clear_single_step(struct task_struct *task)
+static void clear_single_step(struct task_struct *task)
 {
 {
 	task->thread.per_info.single_step = 0;
 	task->thread.per_info.single_step = 0;
 	FixPerRegisters(task);
 	FixPerRegisters(task);
@@ -232,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
 		 */
 		 */
 		if (addr == (addr_t) &dummy->regs.psw.mask &&
 		if (addr == (addr_t) &dummy->regs.psw.mask &&
 #ifdef CONFIG_COMPAT
 #ifdef CONFIG_COMPAT
-		    data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
+		    data != PSW_MASK_MERGE(psw_user32_bits, data) &&
 #endif
 #endif
-		    data != PSW_MASK_MERGE(PSW_USER_BITS, data))
+		    data != PSW_MASK_MERGE(psw_user_bits, data))
 			/* Invalid psw mask. */
 			/* Invalid psw mask. */
 			return -EINVAL;
 			return -EINVAL;
 #ifndef CONFIG_64BIT
 #ifndef CONFIG_64BIT
@@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 		if (copied != sizeof(tmp))
 			return -EIO;
 			return -EIO;
-		return put_user(tmp, (unsigned long __user *) data);
+		return put_user(tmp, (unsigned long __force __user *) data);
 
 
 	case PTRACE_PEEKUSR:
 	case PTRACE_PEEKUSR:
 		/* read the word at location addr in the USER area. */
 		/* read the word at location addr in the USER area. */
@@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
 
 
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __user *) addr,
+		if (copy_from_user(&parea, (void __force __user *) addr,
 							sizeof(parea)))
 							sizeof(parea)))
 			return -EFAULT;
 			return -EFAULT;
 		addr = parea.kernel_addr;
 		addr = parea.kernel_addr;
@@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
 			if (request == PTRACE_PEEKUSR_AREA)
 			if (request == PTRACE_PEEKUSR_AREA)
 				ret = peek_user(child, addr, data);
 				ret = peek_user(child, addr, data);
 			else {
 			else {
-				addr_t tmp;
-				if (get_user (tmp, (addr_t __user *) data))
+				addr_t utmp;
+				if (get_user(utmp,
+					     (addr_t __force __user *) data))
 					return -EFAULT;
 					return -EFAULT;
-				ret = poke_user(child, addr, tmp);
+				ret = poke_user(child, addr, utmp);
 			}
 			}
 			if (ret)
 			if (ret)
 				return ret;
 				return ret;
@@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Fake a 31 bit psw mask. */
 			/* Fake a 31 bit psw mask. */
 			tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
 			tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
-			tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
+			tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Fake a 31 bit psw address. */
 			/* Fake a 31 bit psw address. */
 			tmp = (__u32) task_pt_regs(child)->psw.addr |
 			tmp = (__u32) task_pt_regs(child)->psw.addr |
@@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
 		 */
 		 */
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Build a 64 bit psw mask from 31 bit mask. */
 			/* Build a 64 bit psw mask from 31 bit mask. */
-			if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
+			if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
 				/* Invalid psw mask. */
 				/* Invalid psw mask. */
 				return -EINVAL;
 				return -EINVAL;
 			task_pt_regs(child)->psw.mask =
 			task_pt_regs(child)->psw.mask =
-				PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
+				PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Build a 64 bit psw address from 31 bit address. */
 			/* Build a 64 bit psw address from 31 bit address. */
 			task_pt_regs(child)->psw.addr =
 			task_pt_regs(child)->psw.addr =
@@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 		if (copied != sizeof(tmp))
 		if (copied != sizeof(tmp))
 			return -EIO;
 			return -EIO;
-		return put_user(tmp, (unsigned int __user *) data);
+		return put_user(tmp, (unsigned int __force __user *) data);
 
 
 	case PTRACE_PEEKUSR:
 	case PTRACE_PEEKUSR:
 		/* read the word at location addr in the USER area. */
 		/* read the word at location addr in the USER area. */
@@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 
 
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
-		if (copy_from_user(&parea, (void __user *) addr,
+		if (copy_from_user(&parea, (void __force __user *) addr,
 							sizeof(parea)))
 							sizeof(parea)))
 			return -EFAULT;
 			return -EFAULT;
 		addr = parea.kernel_addr;
 		addr = parea.kernel_addr;
@@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 			if (request == PTRACE_PEEKUSR_AREA)
 			if (request == PTRACE_PEEKUSR_AREA)
 				ret = peek_user_emu31(child, addr, data);
 				ret = peek_user_emu31(child, addr, data);
 			else {
 			else {
-				__u32 tmp;
-				if (get_user (tmp, (__u32 __user *) data))
+				__u32 utmp;
+				if (get_user(utmp,
+					     (__u32 __force __user *) data))
 					return -EFAULT;
 					return -EFAULT;
-				ret = poke_user_emu31(child, addr, tmp);
+				ret = poke_user_emu31(child, addr, utmp);
 			}
 			}
 			if (ret)
 			if (ret)
 				return ret;
 				return ret;
@@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 		return 0;
 		return 0;
 	case PTRACE_GETEVENTMSG:
 	case PTRACE_GETEVENTMSG:
 		return put_user((__u32) child->ptrace_message,
 		return put_user((__u32) child->ptrace_message,
-				(unsigned int __user *) data);
+				(unsigned int __force __user *) data);
 	case PTRACE_GETSIGINFO:
 	case PTRACE_GETSIGINFO:
 		if (child->last_siginfo == NULL)
 		if (child->last_siginfo == NULL)
 			return -EINVAL;
 			return -EINVAL;
-		return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
+		return copy_siginfo_to_user32((compat_siginfo_t
+					       __force __user *) data,
 					      child->last_siginfo);
 					      child->last_siginfo);
 	case PTRACE_SETSIGINFO:
 	case PTRACE_SETSIGINFO:
 		if (child->last_siginfo == NULL)
 		if (child->last_siginfo == NULL)
 			return -EINVAL;
 			return -EINVAL;
 		return copy_siginfo_from_user32(child->last_siginfo,
 		return copy_siginfo_from_user32(child->last_siginfo,
-						(compat_siginfo_t __user *) data);
+						(compat_siginfo_t
+						 __force __user *) data);
 	}
 	}
 	return ptrace_request(child, request, addr, data);
 	return ptrace_request(child, request, addr, data);
 }
 }

+ 0 - 90
arch/s390/kernel/reset.S

@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/reset.S
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- *		 Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#include <asm/ptrace.h>
-#include <asm/lowcore.h>
-
-#ifdef CONFIG_64BIT
-
-	.globl	reset_mcck_handler
-reset_mcck_handler:
-	basr	%r13,0
-0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	lg	%r1,s390_reset_mcck_handler-0b(%r13)
-	ltgr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-1:	la	%r1,4095
-	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
-	lpswe	__LC_MCK_OLD_PSW
-
-	.globl	s390_reset_mcck_handler
-s390_reset_mcck_handler:
-	.quad	0
-
-	.globl	reset_pgm_handler
-reset_pgm_handler:
-	stmg	%r0,%r15,__LC_SAVE_AREA
-	basr	%r13,0
-0:	lg	%r15,__LC_PANIC_STACK	# load panic stack
-	aghi	%r15,-STACK_FRAME_OVERHEAD
-	lg	%r1,s390_reset_pgm_handler-0b(%r13)
-	ltgr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-	lmg	%r0,%r15,__LC_SAVE_AREA
-	lpswe	__LC_PGM_OLD_PSW
-1:	lpswe	disabled_wait_psw-0b(%r13)
-	.globl s390_reset_pgm_handler
-s390_reset_pgm_handler:
-	.quad	0
-	.align	8
-disabled_wait_psw:
-	.quad	0x0002000180000000,0x0000000000000000 + reset_pgm_handler
-
-#else /* CONFIG_64BIT */
-
-	.globl	reset_mcck_handler
-reset_mcck_handler:
-	basr	%r13,0
-0:	l	%r15,__LC_PANIC_STACK	# load panic stack
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	l	%r1,s390_reset_mcck_handler-0b(%r13)
-	ltr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-1:	lm	%r0,%r15,__LC_GPREGS_SAVE_AREA
-	lpsw	__LC_MCK_OLD_PSW
-
-	.globl	s390_reset_mcck_handler
-s390_reset_mcck_handler:
-	.long	0
-
-	.globl	reset_pgm_handler
-reset_pgm_handler:
-	stm	%r0,%r15,__LC_SAVE_AREA
-	basr	%r13,0
-0:	l	%r15,__LC_PANIC_STACK	# load panic stack
-	ahi	%r15,-STACK_FRAME_OVERHEAD
-	l	%r1,s390_reset_pgm_handler-0b(%r13)
-	ltr	%r1,%r1
-	jz	1f
-	basr	%r14,%r1
-	lm	%r0,%r15,__LC_SAVE_AREA
-	lpsw	__LC_PGM_OLD_PSW
-
-1:	lpsw	disabled_wait_psw-0b(%r13)
-	.globl	s390_reset_pgm_handler
-s390_reset_pgm_handler:
-	.long	0
-disabled_wait_psw:
-	.align 8
-	.long	0x000a0000,0x00000000 + reset_pgm_handler
-
-#endif /* CONFIG_64BIT */

+ 3 - 5
arch/s390/kernel/s390_ext.c

@@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, unsigned short code)
 		 * Make sure that the i/o interrupt did not "overtake"
 		 * Make sure that the i/o interrupt did not "overtake"
 		 * the last HZ timer interrupt.
 		 * the last HZ timer interrupt.
 		 */
 		 */
-		account_ticks();
+		account_ticks(S390_lowcore.int_clock);
 	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
 	kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
         index = ext_hash(code);
         index = ext_hash(code);
 	for (p = ext_int_hash[index]; p; p = p->next) {
 	for (p = ext_int_hash[index]; p; p = p->next) {
-		if (likely(p->code == code)) {
-			if (likely(p->handler))
-				p->handler(code);
-		}
+		if (likely(p->code == code))
+			p->handler(code);
 	}
 	}
 	irq_exit();
 	irq_exit();
 	set_irq_regs(old_regs);
 	set_irq_regs(old_regs);

+ 133 - 22
arch/s390/kernel/setup.c

@@ -38,6 +38,8 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/pfn.h>
 #include <linux/pfn.h>
+#include <linux/ctype.h>
+#include <linux/reboot.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/system.h>
@@ -49,6 +51,14 @@
 #include <asm/page.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
 #include <asm/sections.h>
+#include <asm/ebcdic.h>
+#include <asm/compat.h>
+
+long psw_kernel_bits	= (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
+			   PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
+long psw_user_bits	= (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			   PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			   PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
 
 
 /*
 /*
  * User copy operations.
  * User copy operations.
@@ -117,9 +127,9 @@ void __devinit cpu_init (void)
  */
  */
 char vmhalt_cmd[128] = "";
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
 char vmpoff_cmd[128] = "";
-char vmpanic_cmd[128] = "";
+static char vmpanic_cmd[128] = "";
 
 
-static inline void strncpy_skip_quote(char *dst, char *src, int n)
+static void strncpy_skip_quote(char *dst, char *src, int n)
 {
 {
         int sx, dx;
         int sx, dx;
 
 
@@ -275,10 +285,6 @@ static void __init conmode_default(void)
 }
 }
 
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
-extern void machine_restart_smp(char *);
-extern void machine_halt_smp(void);
-extern void machine_power_off_smp(void);
-
 void (*_machine_restart)(char *command) = machine_restart_smp;
 void (*_machine_restart)(char *command) = machine_restart_smp;
 void (*_machine_halt)(void) = machine_halt_smp;
 void (*_machine_halt)(void) = machine_halt_smp;
 void (*_machine_power_off)(void) = machine_power_off_smp;
 void (*_machine_power_off)(void) = machine_power_off_smp;
@@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(char *p)
 }
 }
 early_param("ipldelay", early_parse_ipldelay);
 early_param("ipldelay", early_parse_ipldelay);
 
 
+#ifdef CONFIG_S390_SWITCH_AMODE
+unsigned int switch_amode = 0;
+EXPORT_SYMBOL_GPL(switch_amode);
+
+static void set_amode_and_uaccess(unsigned long user_amode,
+				  unsigned long user32_amode)
+{
+	psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
+			PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+#ifdef CONFIG_COMPAT
+	psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
+			  PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+			  PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+	psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
+			  PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+			  PSW32_MASK_PSTATE;
+#endif
+	psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+			  PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
+
+	if (MACHINE_HAS_MVCOS) {
+		printk("mvcos available.\n");
+		memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+	} else {
+		printk("mvcos not available.\n");
+		memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+	}
+}
+
+/*
+ * Switch kernel/user addressing modes?
+ */
+static int __init early_parse_switch_amode(char *p)
+{
+	switch_amode = 1;
+	return 0;
+}
+early_param("switch_amode", early_parse_switch_amode);
+
+#else /* CONFIG_S390_SWITCH_AMODE */
+static inline void set_amode_and_uaccess(unsigned long user_amode,
+					 unsigned long user32_amode)
+{
+}
+#endif /* CONFIG_S390_SWITCH_AMODE */
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+unsigned int s390_noexec = 0;
+EXPORT_SYMBOL_GPL(s390_noexec);
+
+/*
+ * Enable execute protection?
+ */
+static int __init early_parse_noexec(char *p)
+{
+	if (!strncmp(p, "off", 3))
+		return 0;
+	switch_amode = 1;
+	s390_noexec = 1;
+	return 0;
+}
+early_param("noexec", early_parse_noexec);
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+static void setup_addressing_mode(void)
+{
+	if (s390_noexec) {
+		printk("S390 execute protection active, ");
+		set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+		return;
+	}
+	if (switch_amode) {
+		printk("S390 address spaces switched, ");
+		set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+	}
+}
+
 static void __init
 static void __init
 setup_lowcore(void)
 setup_lowcore(void)
 {
 {
@@ -402,19 +486,21 @@ setup_lowcore(void)
 	lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
 	lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
 	lc->restart_psw.addr =
 	lc->restart_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
 		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-	lc->external_new_psw.mask = PSW_KERNEL_BITS;
+	if (switch_amode)
+		lc->restart_psw.mask |= PSW_ASC_HOME;
+	lc->external_new_psw.mask = psw_kernel_bits;
 	lc->external_new_psw.addr =
 	lc->external_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
 		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
-	lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
 	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
 	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
-	lc->program_new_psw.mask = PSW_KERNEL_BITS;
+	lc->program_new_psw.mask = psw_kernel_bits;
 	lc->program_new_psw.addr =
 	lc->program_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
 		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
 	lc->mcck_new_psw.mask =
 	lc->mcck_new_psw.mask =
-		PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
+		psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
 	lc->mcck_new_psw.addr =
 	lc->mcck_new_psw.addr =
 		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
 		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
-	lc->io_new_psw.mask = PSW_KERNEL_BITS;
+	lc->io_new_psw.mask = psw_kernel_bits;
 	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
 	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
 	lc->ipl_device = S390_lowcore.ipl_device;
 	lc->ipl_device = S390_lowcore.ipl_device;
 	lc->jiffy_timer = -1LL;
 	lc->jiffy_timer = -1LL;
@@ -439,7 +525,7 @@ setup_lowcore(void)
 static void __init
 static void __init
 setup_resources(void)
 setup_resources(void)
 {
 {
-	struct resource *res;
+	struct resource *res, *sub_res;
 	int i;
 	int i;
 
 
 	code_resource.start = (unsigned long) &_text;
 	code_resource.start = (unsigned long) &_text;
@@ -464,8 +550,38 @@ setup_resources(void)
 		res->start = memory_chunk[i].addr;
 		res->start = memory_chunk[i].addr;
 		res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
 		res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
 		request_resource(&iomem_resource, res);
 		request_resource(&iomem_resource, res);
-		request_resource(res, &code_resource);
-		request_resource(res, &data_resource);
+
+		if (code_resource.start >= res->start  &&
+			code_resource.start <= res->end &&
+			code_resource.end > res->end) {
+			sub_res = alloc_bootmem_low(sizeof(struct resource));
+			memcpy(sub_res, &code_resource,
+				sizeof(struct resource));
+			sub_res->end = res->end;
+			code_resource.start = res->end + 1;
+			request_resource(res, sub_res);
+		}
+
+		if (code_resource.start >= res->start &&
+			code_resource.start <= res->end &&
+			code_resource.end <= res->end)
+			request_resource(res, &code_resource);
+
+		if (data_resource.start >= res->start &&
+			data_resource.start <= res->end &&
+			data_resource.end > res->end) {
+			sub_res = alloc_bootmem_low(sizeof(struct resource));
+			memcpy(sub_res, &data_resource,
+				sizeof(struct resource));
+			sub_res->end = res->end;
+			data_resource.start = res->end + 1;
+			request_resource(res, sub_res);
+		}
+
+		if (data_resource.start >= res->start &&
+			data_resource.start <= res->end &&
+			data_resource.end <= res->end)
+			request_resource(res, &data_resource);
 	}
 	}
 }
 }
 
 
@@ -495,16 +611,13 @@ static void __init setup_memory_end(void)
 	}
 	}
 	if (!memory_end)
 	if (!memory_end)
 		memory_end = memory_size;
 		memory_end = memory_size;
-	if (real_size > memory_end)
-		printk("More memory detected than supported. Unused: %luk\n",
-		       (real_size - memory_end) >> 10);
 }
 }
 
 
 static void __init
 static void __init
 setup_memory(void)
 setup_memory(void)
 {
 {
         unsigned long bootmap_size;
         unsigned long bootmap_size;
-	unsigned long start_pfn, end_pfn, init_pfn;
+	unsigned long start_pfn, end_pfn;
 	int i;
 	int i;
 
 
 	/*
 	/*
@@ -514,10 +627,6 @@ setup_memory(void)
 	start_pfn = PFN_UP(__pa(&_end));
 	start_pfn = PFN_UP(__pa(&_end));
 	end_pfn = max_pfn = PFN_DOWN(memory_end);
 	end_pfn = max_pfn = PFN_DOWN(memory_end);
 
 
-	/* Initialize storage key for kernel pages */
-	for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
-		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
-
 #ifdef CONFIG_BLK_DEV_INITRD
 #ifdef CONFIG_BLK_DEV_INITRD
 	/*
 	/*
 	 * Move the initrd in case the bitmap of the bootmem allocater
 	 * Move the initrd in case the bitmap of the bootmem allocater
@@ -651,6 +760,7 @@ setup_arch(char **cmdline_p)
 	parse_early_param();
 	parse_early_param();
 
 
 	setup_memory_end();
 	setup_memory_end();
+	setup_addressing_mode();
 	setup_memory();
 	setup_memory();
 	setup_resources();
 	setup_resources();
 	setup_lowcore();
 	setup_lowcore();
@@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         struct cpuinfo_S390 *cpuinfo;
         struct cpuinfo_S390 *cpuinfo;
 	unsigned long n = (unsigned long) v - 1;
 	unsigned long n = (unsigned long) v - 1;
 
 
+	s390_adjust_jiffies();
 	preempt_disable();
 	preempt_disable();
 	if (!n) {
 	if (!n) {
 		seq_printf(m, "vendor_id       : IBM/S390\n"
 		seq_printf(m, "vendor_id       : IBM/S390\n"

+ 1 - 1
arch/s390/kernel/signal.c

@@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
 
 
 	/* Copy a 'clean' PSW mask to the user to avoid leaking
 	/* Copy a 'clean' PSW mask to the user to avoid leaking
 	   information about whether PER is currently on.  */
 	   information about whether PER is currently on.  */
-	user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+	user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
 	user_sregs.regs.psw.addr = regs->psw.addr;
 	user_sregs.regs.psw.addr = regs->psw.addr;
 	memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
 	memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
 	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
 	memcpy(&user_sregs.regs.acrs, current->thread.acrs,

+ 12 - 20
arch/s390/kernel/smp.c

@@ -22,23 +22,23 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
-
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
-
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/cache.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/cpu.h>
-
+#include <linux/timex.h>
+#include <asm/setup.h>
 #include <asm/sigp.h>
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
 #include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
 #include <asm/tlbflush.h>
+#include <asm/timer.h>
 
 
 extern volatile int __cpu_logical_map[];
 extern volatile int __cpu_logical_map[];
 
 
@@ -53,12 +53,6 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
 
 
 static struct task_struct *current_set[NR_CPUS];
 static struct task_struct *current_set[NR_CPUS];
 
 
-/*
- * Reboot, halt and power_off routines for SMP.
- */
-extern char vmhalt_cmd[];
-extern char vmpoff_cmd[];
-
 static void smp_ext_bitcall(int, ec_bit_sig);
 static void smp_ext_bitcall(int, ec_bit_sig);
 static void smp_ext_bitcall_others(ec_bit_sig);
 static void smp_ext_bitcall_others(ec_bit_sig);
 
 
@@ -200,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info,
 }
 }
 EXPORT_SYMBOL(smp_call_function_on);
 EXPORT_SYMBOL(smp_call_function_on);
 
 
-static inline void do_send_stop(void)
+static void do_send_stop(void)
 {
 {
         int cpu, rc;
         int cpu, rc;
 
 
@@ -214,7 +208,7 @@ static inline void do_send_stop(void)
 	}
 	}
 }
 }
 
 
-static inline void do_store_status(void)
+static void do_store_status(void)
 {
 {
         int cpu, rc;
         int cpu, rc;
 
 
@@ -230,7 +224,7 @@ static inline void do_store_status(void)
         }
         }
 }
 }
 
 
-static inline void do_wait_for_stop(void)
+static void do_wait_for_stop(void)
 {
 {
 	int cpu;
 	int cpu;
 
 
@@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void)
 void smp_send_stop(void)
 void smp_send_stop(void)
 {
 {
 	/* Disable all interrupts/machine checks */
 	/* Disable all interrupts/machine checks */
-	__load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 
 
         /* write magic number to zero page (absolute 0) */
         /* write magic number to zero page (absolute 0) */
 	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
 	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
@@ -298,7 +292,7 @@ void machine_power_off_smp(void)
  * cpus are handled.
  * cpus are handled.
  */
  */
 
 
-void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(__u16 code)
 {
 {
         unsigned long bits;
         unsigned long bits;
 
 
@@ -385,7 +379,7 @@ struct ec_creg_mask_parms {
 /*
 /*
  * callback for setting/clearing control bits
  * callback for setting/clearing control bits
  */
  */
-void smp_ctl_bit_callback(void *info) {
+static void smp_ctl_bit_callback(void *info) {
 	struct ec_creg_mask_parms *pp = info;
 	struct ec_creg_mask_parms *pp = info;
 	unsigned long cregs[16];
 	unsigned long cregs[16];
 	int i;
 	int i;
@@ -458,17 +452,15 @@ __init smp_count_cpus(void)
 /*
 /*
  *      Activate a secondary processor.
  *      Activate a secondary processor.
  */
  */
-extern void init_cpu_timer(void);
-extern void init_cpu_vtimer(void);
-
 int __devinit start_secondary(void *cpuvoid)
 int __devinit start_secondary(void *cpuvoid)
 {
 {
         /* Setup the cpu */
         /* Setup the cpu */
         cpu_init();
         cpu_init();
 	preempt_disable();
 	preempt_disable();
-        /* init per CPU timer */
+	/* Enable TOD clock interrupts on the secondary cpu. */
         init_cpu_timer();
         init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
 #ifdef CONFIG_VIRT_TIMER
+	/* Enable cpu timer interrupts on the secondary cpu. */
         init_cpu_vtimer();
         init_cpu_vtimer();
 #endif
 #endif
 	/* Enable pfault pseudo page faults on this cpu. */
 	/* Enable pfault pseudo page faults on this cpu. */
@@ -542,7 +534,7 @@ smp_put_cpu(int cpu)
 	spin_unlock_irqrestore(&smp_reserve_lock, flags);
 	spin_unlock_irqrestore(&smp_reserve_lock, flags);
 }
 }
 
 
-static inline int
+static int
 cpu_stopped(int cpu)
 cpu_stopped(int cpu)
 {
 {
 	__u32 status;
 	__u32 status;

+ 5 - 5
arch/s390/kernel/stacktrace.c

@@ -11,11 +11,11 @@
 #include <linux/stacktrace.h>
 #include <linux/stacktrace.h>
 #include <linux/kallsyms.h>
 #include <linux/kallsyms.h>
 
 
-static inline unsigned long save_context_stack(struct stack_trace *trace,
-					       unsigned int *skip,
-					       unsigned long sp,
-					       unsigned long low,
-					       unsigned long high)
+static unsigned long save_context_stack(struct stack_trace *trace,
+					unsigned int *skip,
+					unsigned long sp,
+					unsigned long low,
+					unsigned long high)
 {
 {
 	struct stack_frame *sf;
 	struct stack_frame *sf;
 	struct pt_regs *regs;
 	struct pt_regs *regs;

+ 1119 - 66
arch/s390/kernel/time.c

@@ -37,11 +37,15 @@
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/irq_regs.h>
 #include <asm/timer.h>
 #include <asm/timer.h>
+#include <asm/etr.h>
 
 
 /* change this if you have some constant time drift */
 /* change this if you have some constant time drift */
 #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
 #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
 
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
 /*
 /*
  * Create a small time difference between the timer interrupts
  * Create a small time difference between the timer interrupts
  * on the different cpus to avoid lock contention.
  * on the different cpus to avoid lock contention.
@@ -51,6 +55,7 @@
 #define TICK_SIZE tick
 #define TICK_SIZE tick
 
 
 static ext_int_info_t ext_int_info_cc;
 static ext_int_info_t ext_int_info_cc;
+static ext_int_info_t ext_int_etr_cc;
 static u64 init_timer_cc;
 static u64 init_timer_cc;
 static u64 jiffies_timer_cc;
 static u64 jiffies_timer_cc;
 static u64 xtime_cc;
 static u64 xtime_cc;
@@ -89,29 +94,21 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
 #define s390_do_profile()	do { ; } while(0)
 #define s390_do_profile()	do { ; } while(0)
 #endif /* CONFIG_PROFILING */
 #endif /* CONFIG_PROFILING */
 
 
-
 /*
 /*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * Advance the per cpu tick counter up to the time given with the
+ * "time" argument. The per cpu update consists of accounting
+ * the virtual cpu time, calling update_process_times and calling
+ * the profiling hook. If xtime is before time it is advanced as well.
  */
  */
-void account_ticks(void)
+void account_ticks(u64 time)
 {
 {
-	__u64 tmp;
 	__u32 ticks;
 	__u32 ticks;
+	__u64 tmp;
 
 
 	/* Calculate how many ticks have passed. */
 	/* Calculate how many ticks have passed. */
-	if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
-		/*
-		 * We have to program the clock comparator even if
-		 * no tick has passed. That happens if e.g. an i/o
-		 * interrupt wakes up an idle processor that has
-		 * switched off its hz timer.
-		 */
-		tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-		asm volatile ("SCKC %0" : : "m" (tmp));
+	if (time < S390_lowcore.jiffy_timer)
 		return;
 		return;
-	}
-	tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
+	tmp = time - S390_lowcore.jiffy_timer;
 	if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
 	if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
 		ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
 		ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
 		S390_lowcore.jiffy_timer +=
 		S390_lowcore.jiffy_timer +=
@@ -124,10 +121,6 @@ void account_ticks(void)
 		S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
 		S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
 	}
 	}
 
 
-	/* set clock comparator for next tick */
-	tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-        asm volatile ("SCKC %0" : : "m" (tmp));
-
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 	/*
 	/*
 	 * Do not rely on the boot cpu to do the calls to do_timer.
 	 * Do not rely on the boot cpu to do the calls to do_timer.
@@ -173,7 +166,7 @@ int sysctl_hz_timer = 1;
  * Stop the HZ tick on the current CPU.
  * Stop the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  * Only cpu_idle may call this function.
  */
  */
-static inline void stop_hz_timer(void)
+static void stop_hz_timer(void)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	unsigned long seq, next;
 	unsigned long seq, next;
@@ -210,20 +203,21 @@ static inline void stop_hz_timer(void)
 		if (timer >= jiffies_timer_cc)
 		if (timer >= jiffies_timer_cc)
 			todval = timer;
 			todval = timer;
 	}
 	}
-	asm volatile ("SCKC %0" : : "m" (todval));
+	set_clock_comparator(todval);
 }
 }
 
 
 /*
 /*
  * Start the HZ tick on the current CPU.
  * Start the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  * Only cpu_idle may call this function.
  */
  */
-static inline void start_hz_timer(void)
+static void start_hz_timer(void)
 {
 {
 	BUG_ON(!in_interrupt());
 	BUG_ON(!in_interrupt());
 
 
 	if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
 	if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
 		return;
 		return;
-	account_ticks();
+	account_ticks(get_clock());
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
 	cpu_clear(smp_processor_id(), nohz_cpu_mask);
 	cpu_clear(smp_processor_id(), nohz_cpu_mask);
 }
 }
 
 
@@ -245,7 +239,7 @@ static struct notifier_block nohz_idle_nb = {
 	.notifier_call = nohz_idle_notify,
 	.notifier_call = nohz_idle_notify,
 };
 };
 
 
-void __init nohz_init(void)
+static void __init nohz_init(void)
 {
 {
 	if (register_idle_notifier(&nohz_idle_nb))
 	if (register_idle_notifier(&nohz_idle_nb))
 		panic("Couldn't register idle notifier");
 		panic("Couldn't register idle notifier");
@@ -254,24 +248,57 @@ void __init nohz_init(void)
 #endif
 #endif
 
 
 /*
 /*
- * Start the clock comparator on the current CPU.
+ * Set up per cpu jiffy timer and set the clock comparator.
+ */
+static void setup_jiffy_timer(void)
+{
+	/* Set up clock comparator to next jiffy. */
+	S390_lowcore.jiffy_timer =
+		jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+/*
+ * Set up lowcore and control register of the current cpu to
+ * enable TOD clock and clock comparator interrupts.
  */
  */
 void init_cpu_timer(void)
 void init_cpu_timer(void)
 {
 {
-	unsigned long cr0;
-	__u64 timer;
+	setup_jiffy_timer();
 
 
-	timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
-	timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
-	asm volatile ("SCKC %0" : : "m" (timer));
-        /* allow clock comparator timer interrupt */
-	__ctl_store(cr0, 0, 0);
-        cr0 |= 0x800;
-	__ctl_load(cr0, 0, 0);
+	/* Enable clock comparator timer interrupt. */
+	__ctl_set_bit(0,11);
+
+	/* Always allow ETR external interrupts, even without an ETR. */
+	__ctl_set_bit(0, 4);
 }
 }
 
 
-extern void vtime_init(void);
+static void clock_comparator_interrupt(__u16 code)
+{
+	/* set clock comparator for next tick */
+	set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+static void etr_reset(void);
+static void etr_init(void);
+static void etr_ext_handler(__u16);
+
+/*
+ * Get the TOD clock running.
+ */
+static u64 __init reset_tod_clock(void)
+{
+	u64 time;
+
+	etr_reset();
+	if (store_clock(&time) == 0)
+		return time;
+	/* TOD clock not running. Set the clock to Unix Epoch. */
+	if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+		panic("TOD clock not operational.");
+
+	return TOD_UNIX_EPOCH;
+}
 
 
 static cycle_t read_tod_clock(void)
 static cycle_t read_tod_clock(void)
 {
 {
@@ -295,48 +322,31 @@ static struct clocksource clocksource_tod = {
  */
  */
 void __init time_init(void)
 void __init time_init(void)
 {
 {
-	__u64 set_time_cc;
-	int cc;
-
-        /* kick the TOD clock */
-	asm volatile(
-		"	stck	0(%2)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (cc), "=m" (init_timer_cc)
-		: "a" (&init_timer_cc) : "cc");
-        switch (cc) {
-        case 0: /* clock in set state: all is fine */
-                break;
-        case 1: /* clock in non-set state: FIXME */
-                printk("time_init: TOD clock in non-set state\n");
-                break;
-        case 2: /* clock in error state: FIXME */
-                printk("time_init: TOD clock in error state\n");
-                break;
-        case 3: /* clock in stopped or not-operational state: FIXME */
-                printk("time_init: TOD clock stopped/non-operational\n");
-                break;
-        }
+	init_timer_cc = reset_tod_clock();
+	xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
 	jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
 	jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
 
 
 	/* set xtime */
 	/* set xtime */
-	xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
-	set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
-		(0x3c26700LL*1000000*4096);
-        tod_to_timeval(set_time_cc, &xtime);
+	tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime);
         set_normalized_timespec(&wall_to_monotonic,
         set_normalized_timespec(&wall_to_monotonic,
                                 -xtime.tv_sec, -xtime.tv_nsec);
                                 -xtime.tv_sec, -xtime.tv_nsec);
 
 
 	/* request the clock comparator external interrupt */
 	/* request the clock comparator external interrupt */
-	if (register_early_external_interrupt(0x1004, NULL,
+	if (register_early_external_interrupt(0x1004,
+					      clock_comparator_interrupt,
 					      &ext_int_info_cc) != 0)
 					      &ext_int_info_cc) != 0)
                 panic("Couldn't request external interrupt 0x1004");
                 panic("Couldn't request external interrupt 0x1004");
 
 
 	if (clocksource_register(&clocksource_tod) != 0)
 	if (clocksource_register(&clocksource_tod) != 0)
 		panic("Could not register TOD clock source");
 		panic("Could not register TOD clock source");
 
 
-        init_cpu_timer();
+	/* request the etr external interrupt */
+	if (register_early_external_interrupt(0x1406, etr_ext_handler,
+					      &ext_int_etr_cc) != 0)
+		panic("Couldn't request external interrupt 0x1406");
+
+	/* Enable TOD clock interrupts on the boot cpu. */
+	init_cpu_timer();
 
 
 #ifdef CONFIG_NO_IDLE_HZ
 #ifdef CONFIG_NO_IDLE_HZ
 	nohz_init();
 	nohz_init();
@@ -345,5 +355,1048 @@ void __init time_init(void)
 #ifdef CONFIG_VIRT_TIMER
 #ifdef CONFIG_VIRT_TIMER
 	vtime_init();
 	vtime_init();
 #endif
 #endif
+	etr_init();
+}
+
+/*
+ * External Time Reference (ETR) code.
+ */
+static int etr_port0_online;
+static int etr_port1_online;
+
+static int __init early_parse_etr(char *p)
+{
+	if (strncmp(p, "off", 3) == 0)
+		etr_port0_online = etr_port1_online = 0;
+	else if (strncmp(p, "port0", 5) == 0)
+		etr_port0_online = 1;
+	else if (strncmp(p, "port1", 5) == 0)
+		etr_port1_online = 1;
+	else if (strncmp(p, "on", 2) == 0)
+		etr_port0_online = etr_port1_online = 1;
+	return 0;
+}
+early_param("etr", early_parse_etr);
+
+enum etr_event {
+	ETR_EVENT_PORT0_CHANGE,
+	ETR_EVENT_PORT1_CHANGE,
+	ETR_EVENT_PORT_ALERT,
+	ETR_EVENT_SYNC_CHECK,
+	ETR_EVENT_SWITCH_LOCAL,
+	ETR_EVENT_UPDATE,
+};
+
+enum etr_flags {
+	ETR_FLAG_ENOSYS,
+	ETR_FLAG_EACCES,
+	ETR_FLAG_STEAI,
+};
+
+/*
+ * Valid bit combinations of the eacr register are (x = don't care):
+ * e0 e1 dp p0 p1 ea es sl
+ *  0  0  x  0	0  0  0  0  initial, disabled state
+ *  0  0  x  0	1  1  0  0  port 1 online
+ *  0  0  x  1	0  1  0  0  port 0 online
+ *  0  0  x  1	1  1  0  0  both ports online
+ *  0  1  x  0	1  1  0  0  port 1 online and usable, ETR or PPS mode
+ *  0  1  x  0	1  1  0  1  port 1 online, usable and ETR mode
+ *  0  1  x  0	1  1  1  0  port 1 online, usable, PPS mode, in-sync
+ *  0  1  x  0	1  1  1  1  port 1 online, usable, ETR mode, in-sync
+ *  0  1  x  1	1  1  0  0  both ports online, port 1 usable
+ *  0  1  x  1	1  1  1  0  both ports online, port 1 usable, PPS mode, in-sync
+ *  0  1  x  1	1  1  1  1  both ports online, port 1 usable, ETR mode, in-sync
+ *  1  0  x  1	0  1  0  0  port 0 online and usable, ETR or PPS mode
+ *  1  0  x  1	0  1  0  1  port 0 online, usable and ETR mode
+ *  1  0  x  1	0  1  1  0  port 0 online, usable, PPS mode, in-sync
+ *  1  0  x  1	0  1  1  1  port 0 online, usable, ETR mode, in-sync
+ *  1  0  x  1	1  1  0  0  both ports online, port 0 usable
+ *  1  0  x  1	1  1  1  0  both ports online, port 0 usable, PPS mode, in-sync
+ *  1  0  x  1	1  1  1  1  both ports online, port 0 usable, ETR mode, in-sync
+ *  1  1  x  1	1  1  1  0  both ports online & usable, ETR, in-sync
+ *  1  1  x  1	1  1  1  1  both ports online & usable, ETR, in-sync
+ */
+static struct etr_eacr etr_eacr;
+static u64 etr_tolec;			/* time of last eacr update */
+static unsigned long etr_flags;
+static struct etr_aib etr_port0;
+static int etr_port0_uptodate;
+static struct etr_aib etr_port1;
+static int etr_port1_uptodate;
+static unsigned long etr_events;
+static struct timer_list etr_timer;
+static struct tasklet_struct etr_tasklet;
+static DEFINE_PER_CPU(atomic_t, etr_sync_word);
+
+static void etr_timeout(unsigned long dummy);
+static void etr_tasklet_fn(unsigned long dummy);
+
+/*
+ * The etr 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
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference. This function is what ETR is all about..
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+	atomic_t *sw_ptr;
+	unsigned int sw0, sw1;
+
+	sw_ptr = &get_cpu_var(etr_sync_word);
+	sw0 = atomic_read(sw_ptr);
+	*clock = get_clock();
+	sw1 = atomic_read(sw_ptr);
+	put_cpu_var(etr_sync_sync);
+	if (sw0 == sw1 && (sw0 & 0x80000000U))
+		/* Success: time is in sync. */
+		return 0;
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return -ENOSYS;
+	if (test_bit(ETR_FLAG_EACCES, &etr_flags))
+		return -EACCES;
+	return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void etr_disable_sync_clock(void *dummy)
+{
+	atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+	/*
+	 * Clear the in-sync bit 2^31. All get_sync_clock calls will
+	 * fail until the sync bit is turned back on. In addition
+	 * increase the "sequence" counter to avoid the race of an
+	 * etr event and the complete recovery against get_sync_clock.
+	 */
+	atomic_clear_mask(0x80000000, sw_ptr);
+	atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void etr_enable_sync_clock(void)
+{
+	atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+	atomic_set_mask(0x80000000, sw_ptr);
+}
+
+/*
+ * Reset ETR attachment.
+ */
+static void etr_reset(void)
+{
+	etr_eacr =  (struct etr_eacr) {
+		.e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
+		.p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
+		.es = 0, .sl = 0 };
+	if (etr_setr(&etr_eacr) == 0)
+		etr_tolec = get_clock();
+	else {
+		set_bit(ETR_FLAG_ENOSYS, &etr_flags);
+		if (etr_port0_online || etr_port1_online) {
+			printk(KERN_WARNING "Running on non ETR capable "
+			       "machine, only local mode available.\n");
+			etr_port0_online = etr_port1_online = 0;
+		}
+	}
+}
+
+static void etr_init(void)
+{
+	struct etr_aib aib;
+
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return;
+	/* Check if this machine has the steai instruction. */
+	if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
+		set_bit(ETR_FLAG_STEAI, &etr_flags);
+	setup_timer(&etr_timer, etr_timeout, 0UL);
+	tasklet_init(&etr_tasklet, etr_tasklet_fn, 0);
+	if (!etr_port0_online && !etr_port1_online)
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+	if (etr_port0_online) {
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+	if (etr_port1_online) {
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+}
+
+/*
+ * Two sorts of ETR machine checks. The architecture reads:
+ * "When a machine-check niterruption occurs and if a switch-to-local or
+ *  ETR-sync-check interrupt request is pending but disabled, this pending
+ *  disabled interruption request is indicated and is cleared".
+ * Which means that we can get etr_switch_to_local events from the machine
+ * check handler although the interruption condition is disabled. Lovely..
+ */
+
+/*
+ * Switch to local machine check. This is called when the last usable
+ * ETR port goes inactive. After switch to local the clock is not in sync.
+ */
+void etr_switch_to_local(void)
+{
+	if (!etr_eacr.sl)
+		return;
+	etr_disable_sync_clock(NULL);
+	set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR sync check machine check. This is called when the ETR OTE and the
+ * local clock OTE are farther apart than the ETR sync check tolerance.
+ * After a ETR sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void etr_sync_check(void)
+{
+	if (!etr_eacr.es)
+		return;
+	etr_disable_sync_clock(NULL);
+	set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR external interrupt. There are two causes:
+ * 1) port state change, check the usability of the port
+ * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
+ *    sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
+ *    or ETR-data word 4 (edf4) has changed.
+ */
+static void etr_ext_handler(__u16 code)
+{
+	struct etr_interruption_parameter *intparm =
+		(struct etr_interruption_parameter *) &S390_lowcore.ext_params;
+
+	if (intparm->pc0)
+		/* ETR port 0 state change. */
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+	if (intparm->pc1)
+		/* ETR port 1 state change. */
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+	if (intparm->eai)
+		/*
+		 * ETR port alert on either port 0, 1 or both.
+		 * Both ports are not up-to-date now.
+		 */
+		set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+static void etr_timeout(unsigned long dummy)
+{
+	set_bit(ETR_EVENT_UPDATE, &etr_events);
+	tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * Check if the etr mode is pss.
+ */
+static inline int etr_mode_is_pps(struct etr_eacr eacr)
+{
+	return eacr.es && !eacr.sl;
+}
+
+/*
+ * Check if the etr mode is etr.
+ */
+static inline int etr_mode_is_etr(struct etr_eacr eacr)
+{
+	return eacr.es && eacr.sl;
+}
+
+/*
+ * Check if the port can be used for TOD synchronization.
+ * For PPS mode the port has to receive OTEs. For ETR mode
+ * the port has to receive OTEs, the ETR stepping bit has to
+ * be zero and the validity bits for data frame 1, 2, and 3
+ * have to be 1.
+ */
+static int etr_port_valid(struct etr_aib *aib, int port)
+{
+	unsigned int psc;
+
+	/* Check that this port is receiving OTEs. */
+	if (aib->tsp == 0)
+		return 0;
+
+	psc = port ? aib->esw.psc1 : aib->esw.psc0;
+	if (psc == etr_lpsc_pps_mode)
+		return 1;
+	if (psc == etr_lpsc_operational_step)
+		return !aib->esw.y && aib->slsw.v1 &&
+			aib->slsw.v2 && aib->slsw.v3;
+	return 0;
+}
+
+/*
+ * Check if two ports are on the same network.
+ */
+static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2)
+{
+	// FIXME: any other fields we have to compare?
+	return aib1->edf1.net_id == aib2->edf1.net_id;
+}
+
+/*
+ * Wrapper for etr_stei that converts physical port states
+ * to logical port states to be consistent with the output
+ * of stetr (see etr_psc vs. etr_lpsc).
+ */
+static void etr_steai_cv(struct etr_aib *aib, unsigned int func)
+{
+	BUG_ON(etr_steai(aib, func) != 0);
+	/* Convert port state to logical port state. */
+	if (aib->esw.psc0 == 1)
+		aib->esw.psc0 = 2;
+	else if (aib->esw.psc0 == 0 && aib->esw.p == 0)
+		aib->esw.psc0 = 1;
+	if (aib->esw.psc1 == 1)
+		aib->esw.psc1 = 2;
+	else if (aib->esw.psc1 == 0 && aib->esw.p == 1)
+		aib->esw.psc1 = 1;
+}
+
+/*
+ * Check if the aib a2 is still connected to the same attachment as
+ * aib a1, the etv values differ by one and a2 is valid.
+ */
+static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
+{
+	int state_a1, state_a2;
+
+	/* Paranoia check: e0/e1 should better be the same. */
+	if (a1->esw.eacr.e0 != a2->esw.eacr.e0 ||
+	    a1->esw.eacr.e1 != a2->esw.eacr.e1)
+		return 0;
+
+	/* Still connected to the same etr ? */
+	state_a1 = p ? a1->esw.psc1 : a1->esw.psc0;
+	state_a2 = p ? a2->esw.psc1 : a2->esw.psc0;
+	if (state_a1 == etr_lpsc_operational_step) {
+		if (state_a2 != etr_lpsc_operational_step ||
+		    a1->edf1.net_id != a2->edf1.net_id ||
+		    a1->edf1.etr_id != a2->edf1.etr_id ||
+		    a1->edf1.etr_pn != a2->edf1.etr_pn)
+			return 0;
+	} else if (state_a2 != etr_lpsc_pps_mode)
+		return 0;
+
+	/* The ETV value of a2 needs to be ETV of a1 + 1. */
+	if (a1->edf2.etv + 1 != a2->edf2.etv)
+		return 0;
+
+	if (!etr_port_valid(a2, p))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * The time is "clock". xtime is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
+{
+	unsigned long long delta, ticks;
+	struct timex adjust;
+
+	/*
+	 * We don't have to take the xtime lock because the cpu
+	 * executing etr_adjust_time is running disabled in
+	 * tasklet context and all other cpus are looping in
+	 * etr_sync_cpu_start.
+	 */
+	if (clock > xtime_cc) {
+		/* It is later than we thought. */
+		delta = ticks = clock - xtime_cc;
+		delta = ticks = (delta < delay) ? 0 : delta - delay;
+		delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+		init_timer_cc = init_timer_cc + delta;
+		jiffies_timer_cc = jiffies_timer_cc + delta;
+		xtime_cc = xtime_cc + delta;
+		adjust.offset = ticks * (1000000 / HZ);
+	} else {
+		/* It is earlier than we thought. */
+		delta = ticks = xtime_cc - clock;
+		delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+		init_timer_cc = init_timer_cc - delta;
+		jiffies_timer_cc = jiffies_timer_cc - delta;
+		xtime_cc = xtime_cc - delta;
+		adjust.offset = -ticks * (1000000 / HZ);
+	}
+	if (adjust.offset != 0) {
+		printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+		       adjust.offset);
+		adjust.modes = ADJ_OFFSET_SINGLESHOT;
+		do_adjtimex(&adjust);
+	}
+}
+
+static void etr_sync_cpu_start(void *dummy)
+{
+	int *in_sync = dummy;
+
+	etr_enable_sync_clock();
+	/*
+	 * This looks like a busy wait loop but it isn't. etr_sync_cpus
+	 * is called on all other cpus while the TOD clocks is stopped.
+	 * __udelay will stop the cpu on an enabled wait psw until the
+	 * TOD is running again.
+	 */
+	while (*in_sync == 0)
+		__udelay(1);
+	if (*in_sync != 1)
+		/* Didn't work. Clear per-cpu in sync bit again. */
+		etr_disable_sync_clock(NULL);
+	/*
+	 * This round of TOD syncing is done. Set the clock comparator
+	 * to the next tick and let the processor continue.
+	 */
+	setup_jiffy_timer();
+}
+
+static void etr_sync_cpu_end(void *dummy)
+{
+}
+
+/*
+ * Sync the TOD clock using the port refered to by aibp. This port
+ * has to be enabled and the other port has to be disabled. The
+ * last eacr update has to be more than 1.6 seconds in the past.
+ */
+static int etr_sync_clock(struct etr_aib *aib, int port)
+{
+	struct etr_aib *sync_port;
+	unsigned long long clock, delay;
+	int in_sync, follows;
+	int rc;
+
+	/* Check if the current aib is adjacent to the sync port aib. */
+	sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+	follows = etr_aib_follows(sync_port, aib, port);
+	memcpy(sync_port, aib, sizeof(*aib));
+	if (!follows)
+		return -EAGAIN;
+
+	/*
+	 * Catch all other cpus and make them wait until we have
+	 * successfully synced the clock. smp_call_function will
+	 * return after all other cpus are in etr_sync_cpu_start.
+	 */
+	in_sync = 0;
+	preempt_disable();
+	smp_call_function(etr_sync_cpu_start,&in_sync,0,0);
+	local_irq_disable();
+	etr_enable_sync_clock();
+
+	/* Set clock to next OTE. */
+	__ctl_set_bit(14, 21);
+	__ctl_set_bit(0, 29);
+	clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
+	if (set_clock(clock) == 0) {
+		__udelay(1);	/* Wait for the clock to start. */
+		__ctl_clear_bit(0, 29);
+		__ctl_clear_bit(14, 21);
+		etr_stetr(aib);
+		/* Adjust Linux timing variables. */
+		delay = (unsigned long long)
+			(aib->edf2.etv - sync_port->edf2.etv) << 32;
+		etr_adjust_time(clock, delay);
+		setup_jiffy_timer();
+		/* Verify that the clock is properly set. */
+		if (!etr_aib_follows(sync_port, aib, port)) {
+			/* Didn't work. */
+			etr_disable_sync_clock(NULL);
+			in_sync = -EAGAIN;
+			rc = -EAGAIN;
+		} else {
+			in_sync = 1;
+			rc = 0;
+		}
+	} else {
+		/* Could not set the clock ?!? */
+		__ctl_clear_bit(0, 29);
+		__ctl_clear_bit(14, 21);
+		etr_disable_sync_clock(NULL);
+		in_sync = -EAGAIN;
+		rc = -EAGAIN;
+	}
+	local_irq_enable();
+	smp_call_function(etr_sync_cpu_end,NULL,0,0);
+	preempt_enable();
+	return rc;
+}
+
+/*
+ * Handle the immediate effects of the different events.
+ * The port change event is used for online/offline changes.
+ */
+static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
+{
+	if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events))
+		eacr.es = 0;
+	if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events))
+		eacr.es = eacr.sl = 0;
+	if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events))
+		etr_port0_uptodate = etr_port1_uptodate = 0;
+
+	if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) {
+		if (eacr.e0)
+			/*
+			 * Port change of an enabled port. We have to
+			 * assume that this can have caused an stepping
+			 * port switch.
+			 */
+			etr_tolec = get_clock();
+		eacr.p0 = etr_port0_online;
+		if (!eacr.p0)
+			eacr.e0 = 0;
+		etr_port0_uptodate = 0;
+	}
+	if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) {
+		if (eacr.e1)
+			/*
+			 * Port change of an enabled port. We have to
+			 * assume that this can have caused an stepping
+			 * port switch.
+			 */
+			etr_tolec = get_clock();
+		eacr.p1 = etr_port1_online;
+		if (!eacr.p1)
+			eacr.e1 = 0;
+		etr_port1_uptodate = 0;
+	}
+	clear_bit(ETR_EVENT_UPDATE, &etr_events);
+	return eacr;
+}
+
+/*
+ * Set up a timer that expires after the etr_tolec + 1.6 seconds if
+ * one of the ports needs an update.
+ */
+static void etr_set_tolec_timeout(unsigned long long now)
+{
+	unsigned long micros;
+
+	if ((!etr_eacr.p0 || etr_port0_uptodate) &&
+	    (!etr_eacr.p1 || etr_port1_uptodate))
+		return;
+	micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0;
+	micros = (micros > 1600000) ? 0 : 1600000 - micros;
+	mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1);
+}
+
+/*
+ * Set up a time that expires after 1/2 second.
+ */
+static void etr_set_sync_timeout(void)
+{
+	mod_timer(&etr_timer, jiffies + HZ/2);
+}
+
+/*
+ * Update the aib information for one or both ports.
+ */
+static struct etr_eacr etr_handle_update(struct etr_aib *aib,
+					 struct etr_eacr eacr)
+{
+	/* With both ports disabled the aib information is useless. */
+	if (!eacr.e0 && !eacr.e1)
+		return eacr;
+
+	/* Update port0 or port1 with aib stored in etr_tasklet_fn. */
+	if (aib->esw.q == 0) {
+		/* Information for port 0 stored. */
+		if (eacr.p0 && !etr_port0_uptodate) {
+			etr_port0 = *aib;
+			if (etr_port0_online)
+				etr_port0_uptodate = 1;
+		}
+	} else {
+		/* Information for port 1 stored. */
+		if (eacr.p1 && !etr_port1_uptodate) {
+			etr_port1 = *aib;
+			if (etr_port0_online)
+				etr_port1_uptodate = 1;
+		}
+	}
+
+	/*
+	 * Do not try to get the alternate port aib if the clock
+	 * is not in sync yet.
+	 */
+	if (!eacr.es)
+		return eacr;
+
+	/*
+	 * If steai is available we can get the information about
+	 * the other port immediately. If only stetr is available the
+	 * data-port bit toggle has to be used.
+	 */
+	if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+		if (eacr.p0 && !etr_port0_uptodate) {
+			etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
+			etr_port0_uptodate = 1;
+		}
+		if (eacr.p1 && !etr_port1_uptodate) {
+			etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1);
+			etr_port1_uptodate = 1;
+		}
+	} else {
+		/*
+		 * One port was updated above, if the other
+		 * port is not uptodate toggle dp bit.
+		 */
+		if ((eacr.p0 && !etr_port0_uptodate) ||
+		    (eacr.p1 && !etr_port1_uptodate))
+			eacr.dp ^= 1;
+		else
+			eacr.dp = 0;
+	}
+	return eacr;
+}
+
+/*
+ * Write new etr control register if it differs from the current one.
+ * Return 1 if etr_tolec has been updated as well.
+ */
+static void etr_update_eacr(struct etr_eacr eacr)
+{
+	int dp_changed;
+
+	if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0)
+		/* No change, return. */
+		return;
+	/*
+	 * The disable of an active port of the change of the data port
+	 * bit can/will cause a change in the data port.
+	 */
+	dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 ||
+		(etr_eacr.dp ^ eacr.dp) != 0;
+	etr_eacr = eacr;
+	etr_setr(&etr_eacr);
+	if (dp_changed)
+		etr_tolec = get_clock();
+}
+
+/*
+ * ETR tasklet. In this function you'll find the main logic. In
+ * particular this is the only function that calls etr_update_eacr(),
+ * it "controls" the etr control register.
+ */
+static void etr_tasklet_fn(unsigned long dummy)
+{
+	unsigned long long now;
+	struct etr_eacr eacr;
+	struct etr_aib aib;
+	int sync_port;
+
+	/* Create working copy of etr_eacr. */
+	eacr = etr_eacr;
+
+	/* Check for the different events and their immediate effects. */
+	eacr = etr_handle_events(eacr);
+
+	/* Check if ETR is supposed to be active. */
+	eacr.ea = eacr.p0 || eacr.p1;
+	if (!eacr.ea) {
+		/* Both ports offline. Reset everything. */
+		eacr.dp = eacr.es = eacr.sl = 0;
+		on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+		del_timer_sync(&etr_timer);
+		etr_update_eacr(eacr);
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+		return;
+	}
+
+	/* Store aib to get the current ETR status word. */
+	BUG_ON(etr_stetr(&aib) != 0);
+	etr_port0.esw = etr_port1.esw = aib.esw;	/* Copy status word. */
+	now = get_clock();
+
+	/*
+	 * Update the port information if the last stepping port change
+	 * or data port change is older than 1.6 seconds.
+	 */
+	if (now >= etr_tolec + (1600000 << 12))
+		eacr = etr_handle_update(&aib, eacr);
+
+	/*
+	 * Select ports to enable. The prefered synchronization mode is PPS.
+	 * If a port can be enabled depends on a number of things:
+	 * 1) The port needs to be online and uptodate. A port is not
+	 *    disabled just because it is not uptodate, but it is only
+	 *    enabled if it is uptodate.
+	 * 2) The port needs to have the same mode (pps / etr).
+	 * 3) The port needs to be usable -> etr_port_valid() == 1
+	 * 4) To enable the second port the clock needs to be in sync.
+	 * 5) If both ports are useable and are ETR ports, the network id
+	 *    has to be the same.
+	 * The eacr.sl bit is used to indicate etr mode vs. pps mode.
+	 */
+	if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) {
+		eacr.sl = 0;
+		eacr.e0 = 1;
+		if (!etr_mode_is_pps(etr_eacr))
+			eacr.es = 0;
+		if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode)
+			eacr.e1 = 0;
+		// FIXME: uptodate checks ?
+		else if (etr_port0_uptodate && etr_port1_uptodate)
+			eacr.e1 = 1;
+		sync_port = (etr_port0_uptodate &&
+			     etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
+		eacr.sl = 0;
+		eacr.e0 = 0;
+		eacr.e1 = 1;
+		if (!etr_mode_is_pps(etr_eacr))
+			eacr.es = 0;
+		sync_port = (etr_port1_uptodate &&
+			     etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
+		eacr.sl = 1;
+		eacr.e0 = 1;
+		if (!etr_mode_is_etr(etr_eacr))
+			eacr.es = 0;
+		if (!eacr.es || !eacr.p1 ||
+		    aib.esw.psc1 != etr_lpsc_operational_alt)
+			eacr.e1 = 0;
+		else if (etr_port0_uptodate && etr_port1_uptodate &&
+			 etr_compare_network(&etr_port0, &etr_port1))
+			eacr.e1 = 1;
+		sync_port = (etr_port0_uptodate &&
+			     etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
+		eacr.sl = 1;
+		eacr.e0 = 0;
+		eacr.e1 = 1;
+		if (!etr_mode_is_etr(etr_eacr))
+			eacr.es = 0;
+		sync_port = (etr_port1_uptodate &&
+			     etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+		clear_bit(ETR_FLAG_EACCES, &etr_flags);
+	} else {
+		/* Both ports not usable. */
+		eacr.es = eacr.sl = 0;
+		sync_port = -1;
+		set_bit(ETR_FLAG_EACCES, &etr_flags);
+	}
+
+	/*
+	 * If the clock is in sync just update the eacr and return.
+	 * If there is no valid sync port wait for a port update.
+	 */
+	if (eacr.es || sync_port < 0) {
+		etr_update_eacr(eacr);
+		etr_set_tolec_timeout(now);
+		return;
+	}
+
+	/*
+	 * Prepare control register for clock syncing
+	 * (reset data port bit, set sync check control.
+	 */
+	eacr.dp = 0;
+	eacr.es = 1;
+
+	/*
+	 * Update eacr and try to synchronize the clock. If the update
+	 * of eacr caused a stepping port switch (or if we have to
+	 * assume that a stepping port switch has occured) or the
+	 * clock syncing failed, reset the sync check control bit
+	 * and set up a timer to try again after 0.5 seconds
+	 */
+	etr_update_eacr(eacr);
+	if (now < etr_tolec + (1600000 << 12) ||
+	    etr_sync_clock(&aib, sync_port) != 0) {
+		/* Sync failed. Try again in 1/2 second. */
+		eacr.es = 0;
+		etr_update_eacr(eacr);
+		etr_set_sync_timeout();
+	} else
+		etr_set_tolec_timeout(now);
+}
+
+/*
+ * Sysfs interface functions
+ */
+static struct sysdev_class etr_sysclass = {
+	set_kset_name("etr")
+};
+
+static struct sys_device etr_port0_dev = {
+	.id	= 0,
+	.cls	= &etr_sysclass,
+};
+
+static struct sys_device etr_port1_dev = {
+	.id	= 1,
+	.cls	= &etr_sysclass,
+};
+
+/*
+ * ETR class attributes
+ */
+static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+{
+	return sprintf(buf, "%i\n", etr_port0.esw.p);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
+
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+{
+	char *mode_str;
+
+	if (etr_mode_is_pps(etr_eacr))
+		mode_str = "pps";
+	else if (etr_mode_is_etr(etr_eacr))
+		mode_str = "etr";
+	else
+		mode_str = "local";
+	return sprintf(buf, "%s\n", mode_str);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL);
+
+/*
+ * ETR port attributes
+ */
+static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev)
+{
+	if (dev == &etr_port0_dev)
+		return etr_port0_online ? &etr_port0 : NULL;
+	else
+		return etr_port1_online ? &etr_port1 : NULL;
+}
+
+static ssize_t etr_online_show(struct sys_device *dev, char *buf)
+{
+	unsigned int online;
+
+	online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online;
+	return sprintf(buf, "%i\n", online);
+}
+
+static ssize_t etr_online_store(struct sys_device *dev,
+			      const char *buf, size_t count)
+{
+	unsigned int value;
+
+	value = simple_strtoul(buf, NULL, 0);
+	if (value != 0 && value != 1)
+		return -EINVAL;
+	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+		return -ENOSYS;
+	if (dev == &etr_port0_dev) {
+		if (etr_port0_online == value)
+			return count;	/* Nothing to do. */
+		etr_port0_online = value;
+		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	} else {
+		if (etr_port1_online == value)
+			return count;	/* Nothing to do. */
+		etr_port1_online = value;
+		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+		tasklet_hi_schedule(&etr_tasklet);
+	}
+	return count;
+}
+
+static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store);
+
+static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+		       etr_eacr.e0 : etr_eacr.e1);
+}
+
+static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL);
+
+static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf)
+{
+	if (!etr_port0_online && !etr_port1_online)
+		/* Status word is not uptodate if both ports are offline. */
+		return -ENODATA;
+	return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+		       etr_port0.esw.psc0 : etr_port0.esw.psc1);
+}
+
+static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL);
+
+static ssize_t etr_untuned_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.u);
+}
+
+static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL);
+
+static ssize_t etr_network_id_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.net_id);
+}
+
+static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL);
+
+static ssize_t etr_id_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.etr_id);
+}
+
+static SYSDEV_ATTR(id, 0400, etr_id_show, NULL);
+
+static ssize_t etr_port_number_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v1)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf1.etr_pn);
+}
+
+static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL);
+
+static ssize_t etr_coupled_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.c);
+}
+
+static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL);
+
+static ssize_t etr_local_time_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.blto);
+}
+
+static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL);
+
+static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf)
+{
+	struct etr_aib *aib = etr_aib_from_dev(dev);
+
+	if (!aib || !aib->slsw.v3)
+		return -ENODATA;
+	return sprintf(buf, "%i\n", aib->edf3.buo);
+}
+
+static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL);
+
+static struct sysdev_attribute *etr_port_attributes[] = {
+	&attr_online,
+	&attr_stepping_control,
+	&attr_state_code,
+	&attr_untuned,
+	&attr_network,
+	&attr_id,
+	&attr_port,
+	&attr_coupled,
+	&attr_local_time,
+	&attr_utc_offset,
+	NULL
+};
+
+static int __init etr_register_port(struct sys_device *dev)
+{
+	struct sysdev_attribute **attr;
+	int rc;
+
+	rc = sysdev_register(dev);
+	if (rc)
+		goto out;
+	for (attr = etr_port_attributes; *attr; attr++) {
+		rc = sysdev_create_file(dev, *attr);
+		if (rc)
+			goto out_unreg;
+	}
+	return 0;
+out_unreg:
+	for (; attr >= etr_port_attributes; attr--)
+		sysdev_remove_file(dev, *attr);
+	sysdev_unregister(dev);
+out:
+	return rc;
+}
+
+static void __init etr_unregister_port(struct sys_device *dev)
+{
+	struct sysdev_attribute **attr;
+
+	for (attr = etr_port_attributes; *attr; attr++)
+		sysdev_remove_file(dev, *attr);
+	sysdev_unregister(dev);
+}
+
+static int __init etr_init_sysfs(void)
+{
+	int rc;
+
+	rc = sysdev_class_register(&etr_sysclass);
+	if (rc)
+		goto out;
+	rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port);
+	if (rc)
+		goto out_unreg_class;
+	rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode);
+	if (rc)
+		goto out_remove_stepping_port;
+	rc = etr_register_port(&etr_port0_dev);
+	if (rc)
+		goto out_remove_stepping_mode;
+	rc = etr_register_port(&etr_port1_dev);
+	if (rc)
+		goto out_remove_port0;
+	return 0;
+
+out_remove_port0:
+	etr_unregister_port(&etr_port0_dev);
+out_remove_stepping_mode:
+	sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode);
+out_remove_stepping_port:
+	sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port);
+out_unreg_class:
+	sysdev_class_unregister(&etr_sysclass);
+out:
+	return rc;
 }
 }
 
 
+device_initcall(etr_init_sysfs);

+ 15 - 9
arch/s390/kernel/traps.c

@@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer)
 	return buffer;
 	return buffer;
 }
 }
 
 
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
 
 
 void die(const char * str, struct pt_regs * regs, long err)
 void die(const char * str, struct pt_regs * regs, long err)
 {
 {
@@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_regs *regs)
 		force_sig(SIGTRAP, current);
 		force_sig(SIGTRAP, current);
 }
 }
 
 
-asmlinkage void
-default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs * regs, long interruption_code)
 {
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
 		local_irq_enable();
 		local_irq_enable();
@@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * regs, long interruption_code)
 }
 }
 
 
 #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
 #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+static void name(struct pt_regs * regs, long interruption_code) \
 { \
 { \
         siginfo_t info; \
         siginfo_t info; \
         info.si_signo = signr; \
         info.si_signo = signr; \
@@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
 		"floating point exception", regs, &si);
 		"floating point exception", regs, &si);
 }
 }
 
 
-asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs * regs, long interruption_code)
 {
 {
 	siginfo_t info;
 	siginfo_t info;
         __u8 opcode[6];
         __u8 opcode[6];
@@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 #endif
 #endif
 		} else
 		} else
 			signal = SIGILL;
 			signal = SIGILL;
-	} else
-		signal = SIGILL;
+	} else {
+		/*
+		 * If we get an illegal op in kernel mode, send it through the
+		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
+		 */
+		if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+			       3, SIGTRAP) != NOTIFY_STOP)
+			signal = SIGILL;
+	}
 
 
 #ifdef CONFIG_MATHEMU
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
         if (signal == SIGFPE)
@@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
 	      ILL_ILLOPN, get_check_address(regs));
 	      ILL_ILLOPN, get_check_address(regs));
 #endif
 #endif
 
 
-asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs * regs, long interruption_code)
 {
 {
 	__u16 __user *location;
 	__u16 __user *location;
 	int signal = 0;
 	int signal = 0;
@@ -675,7 +681,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 	}
 	}
 }
 }
 
 
-asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs * regs, long int_code)
 {
 {
         siginfo_t info;
         siginfo_t info;
 
 

+ 7 - 6
arch/s390/kernel/vmlinux.lds.S

@@ -31,18 +31,19 @@ SECTIONS
 
 
   _etext = .;			/* End of text section */
   _etext = .;			/* End of text section */
 
 
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
   RODATA
   RODATA
 
 
 #ifdef CONFIG_SHARED_KERNEL
 #ifdef CONFIG_SHARED_KERNEL
   . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
   . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
+#endif
 
 
+  . = ALIGN(4096);
   _eshared = .;			/* End of shareable data */
   _eshared = .;			/* End of shareable data */
-#endif
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
 
 
   .data : {			/* Data */
   .data : {			/* Data */
 	*(.data)
 	*(.data)

+ 5 - 5
arch/s390/kernel/vtime.c

@@ -25,7 +25,7 @@
 #include <asm/irq_regs.h>
 #include <asm/irq_regs.h>
 
 
 static ext_int_info_t ext_int_info_timer;
 static ext_int_info_t ext_int_info_timer;
-DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
 /*
@@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
 void init_cpu_vtimer(void)
 void init_cpu_vtimer(void)
 {
 {
 	struct vtimer_queue *vt_list;
 	struct vtimer_queue *vt_list;
-	unsigned long cr0;
 
 
 	/* kick the virtual timer */
 	/* kick the virtual timer */
 	S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
 	S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
 	S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
 	S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
 	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
 	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
 	asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
 	asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
-	__ctl_store(cr0, 0, 0);
-	cr0 |= 0x400;
-	__ctl_load(cr0, 0, 0);
+
+	/* enable cpu timer interrupts */
+	__ctl_set_bit(0,10);
 
 
 	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
 	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
 	INIT_LIST_HEAD(&vt_list->list);
 	INIT_LIST_HEAD(&vt_list->list);
@@ -572,6 +571,7 @@ void __init vtime_init(void)
 	if (register_idle_notifier(&vtimer_idle_nb))
 	if (register_idle_notifier(&vtimer_idle_nb))
 		panic("Couldn't register idle notifier");
 		panic("Couldn't register idle notifier");
 
 
+	/* Enable cpu timer interrupts on the boot cpu. */
 	init_cpu_vtimer();
 	init_cpu_vtimer();
 }
 }
 
 

+ 1 - 1
arch/s390/lib/Makefile

@@ -4,7 +4,7 @@
 
 
 EXTRA_AFLAGS := -traditional
 EXTRA_AFLAGS := -traditional
 
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
 lib-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
 lib-$(CONFIG_SMP) += spinlock.o

+ 34 - 14
arch/s390/lib/delay.c

@@ -1,5 +1,5 @@
 /*
 /*
- *  arch/s390/kernel/delay.c
+ *  arch/s390/lib/delay.c
  *    Precise Delay Loops for S390
  *    Precise Delay Loops for S390
  *
  *
  *  S390 version
  *  S390 version
@@ -13,10 +13,8 @@
 
 
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
+#include <linux/timex.h>
+#include <linux/irqflags.h>
 
 
 void __delay(unsigned long loops)
 void __delay(unsigned long loops)
 {
 {
@@ -31,17 +29,39 @@ void __delay(unsigned long loops)
 }
 }
 
 
 /*
 /*
- * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
- * of the virtual PU inbetween to avoid congestion.
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
  */
  */
 void __udelay(unsigned long usecs)
 void __udelay(unsigned long usecs)
 {
 {
-	uint64_t start_cc;
+	u64 end, time, jiffy_timer = 0;
+	unsigned long flags, cr0, mask, dummy;
+
+	local_irq_save(flags);
+	if (raw_irqs_disabled_flags(flags)) {
+		jiffy_timer = S390_lowcore.jiffy_timer;
+		S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
+		__ctl_store(cr0, 0, 0);
+		dummy = (cr0 & 0xffff00e0) | 0x00000800;
+		__ctl_load(dummy , 0, 0);
+		mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+	} else
+		mask = psw_kernel_bits | PSW_MASK_WAIT |
+			PSW_MASK_EXT | PSW_MASK_IO;
+
+	end = get_clock() + ((u64) usecs << 12);
+	do {
+		time = end < S390_lowcore.jiffy_timer ?
+			end : S390_lowcore.jiffy_timer;
+		set_clock_comparator(time);
+		trace_hardirqs_on();
+		__load_psw_mask(mask);
+		local_irq_disable();
+	} while (get_clock() < end);
 
 
-        if (usecs == 0)
-                return;
-	start_cc = get_clock();
-        do {
-		cpu_relax();
-	} while (((get_clock() - start_cc)/4096) < usecs);
+	if (raw_irqs_disabled_flags(flags)) {
+		__ctl_load(cr0, 0, 0);
+		S390_lowcore.jiffy_timer = jiffy_timer;
+	}
+	set_clock_comparator(S390_lowcore.jiffy_timer);
+	local_irq_restore(flags);
 }
 }

+ 77 - 0
arch/s390/lib/qrnnd.S

@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+	.text
+	.globl __udiv_qrnnd
+__udiv_qrnnd:
+	st    %r2,24(%r15)	  # store pointer to reminder for later
+	lr    %r0,%r3		  # reload n
+	lr    %r1,%r4
+	ltr   %r2,%r5		  # reload and test divisor
+	jp    5f
+	# divisor >= 0x80000000
+	srdl  %r0,2		  # n/4
+	srl   %r2,1		  # d/2
+	slr   %r1,%r2		  # special case if last bit of d is set
+	brc   3,0f		  #  (n/4) div (n/2) can overflow by 1
+	ahi   %r0,-1		  #  trick: subtract n/2, then divide
+0:	dr    %r0,%r2		  # signed division
+	ahi   %r1,1		  #  trick part 2: add 1 to the quotient
+	# now (n >> 2) = (d >> 1) * %r1 + %r0
+	lhi   %r3,1
+	nr    %r3,%r1		  # test last bit of q
+	jz    1f
+	alr   %r0,%r2		  # add (d>>1) to r
+1:	srl   %r1,1		  # q >>= 1
+	# now (n >> 2) = (d&-2) * %r1 + %r0
+	lhi   %r3,1
+	nr    %r3,%r5		  # test last bit of d
+	jz    2f
+	slr   %r0,%r1		  # r -= q
+	brc   3,2f		  # borrow ?
+	alr   %r0,%r5		  # r += d
+	ahi   %r1,-1
+2:	# now (n >> 2) = d * %r1 + %r0
+	alr   %r1,%r1		  # q <<= 1
+	alr   %r0,%r0		  # r <<= 1
+	brc   12,3f		  # overflow on r ?
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+3:	lhi   %r3,2
+	nr    %r3,%r4		  # test next to last bit of n
+	jz    4f
+	ahi   %r0,1		  # r += 1
+4:	clr   %r0,%r5		  # r >= d ?
+	jl    6f
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+	# now (n >> 1) = d * %r1 + %r0
+	j     6f
+5:	# divisor < 0x80000000
+	srdl  %r0,1
+	dr    %r0,%r2		  # signed division
+	# now (n >> 1) = d * %r1 + %r0
+6:	alr   %r1,%r1		  # q <<= 1
+	alr   %r0,%r0		  # r <<= 1
+	brc   12,7f		  # overflow on r ?
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+7:	lhi   %r3,1
+	nr    %r3,%r4		  # isolate last bit of n
+	alr   %r0,%r3		  # r += (n & 1)
+	clr   %r0,%r5		  # r >= d ?
+	jl    8f
+	slr   %r0,%r5		  # r -= d
+	ahi   %r1,1		  # q += 1
+8:	# now n = d * %r1 + %r0
+	l     %r2,24(%r15)
+	st    %r0,0(%r2)
+	lr    %r2,%r1
+	br    %r14
+	.end	__udiv_qrnnd

+ 23 - 0
arch/s390/lib/uaccess.h

@@ -0,0 +1,23 @@
+/*
+ *  arch/s390/uaccess.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __ARCH_S390_LIB_UACCESS_H
+#define __ARCH_S390_LIB_UACCESS_H
+
+extern size_t copy_from_user_std(size_t, const void __user *, void *);
+extern size_t copy_to_user_std(size_t, void __user *, const void *);
+extern size_t strnlen_user_std(size_t, const char __user *);
+extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
+extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_op_std(int, int __user *, int, int *);
+
+extern size_t copy_from_user_pt(size_t, const void __user *, void *);
+extern size_t copy_to_user_pt(size_t, void __user *, const void *);
+extern int futex_atomic_op_pt(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+
+#endif /* __ARCH_S390_LIB_UACCESS_H */

+ 63 - 15
arch/s390/lib/uaccess_mvcos.c

@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 
 #ifndef __s390x__
 #ifndef __s390x__
 #define AHI	"ahi"
 #define AHI	"ahi"
@@ -27,10 +28,7 @@
 #define SLR	"slgr"
 #define SLR	"slgr"
 #endif
 #endif
 
 
-extern size_t copy_from_user_std(size_t, const void __user *, void *);
-extern size_t copy_to_user_std(size_t, void __user *, const void *);
-
-size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
 {
 {
 	register unsigned long reg0 asm("0") = 0x81UL;
 	register unsigned long reg0 asm("0") = 0x81UL;
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
@@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
 	return size;
 	return size;
 }
 }
 
 
-size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
 {
 {
 	if (size <= 256)
 	if (size <= 256)
 		return copy_from_user_std(size, ptr, x);
 		return copy_from_user_std(size, ptr, x);
 	return copy_from_user_mvcos(size, ptr, x);
 	return copy_from_user_mvcos(size, ptr, x);
 }
 }
 
 
-size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
 {
 {
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
@@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
 	return size;
 	return size;
 }
 }
 
 
-size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
+				       const void *x)
 {
 {
 	if (size <= 256)
 	if (size <= 256)
 		return copy_to_user_std(size, ptr, x);
 		return copy_to_user_std(size, ptr, x);
 	return copy_to_user_mvcos(size, ptr, x);
 	return copy_to_user_mvcos(size, ptr, x);
 }
 }
 
 
-size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_mvcos(size_t size, void __user *to,
+				 const void __user *from)
 {
 {
 	register unsigned long reg0 asm("0") = 0x810081UL;
 	register unsigned long reg0 asm("0") = 0x810081UL;
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
@@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
 	return size;
 	return size;
 }
 }
 
 
-size_t clear_user_mvcos(size_t size, void __user *to)
+static size_t clear_user_mvcos(size_t size, void __user *to)
 {
 {
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	register unsigned long reg0 asm("0") = 0x810000UL;
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
@@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to)
 	return size;
 	return size;
 }
 }
 
 
-extern size_t strnlen_user_std(size_t, const char __user *);
-extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_op(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg(int __user *, int, int);
+static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+{
+	char buf[256];
+	int rc;
+	size_t done, len, len_str;
+
+	done = 0;
+	do {
+		len = min(count - done, (size_t) 256);
+		rc = uaccess.copy_from_user(len, src + done, buf);
+		if (unlikely(rc == len))
+			return 0;
+		len -= rc;
+		len_str = strnlen(buf, len);
+		done += len_str;
+	} while ((len_str == len) && (done < count));
+	return done + 1;
+}
+
+static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
+				      char *dst)
+{
+	int rc;
+	size_t done, len, len_str;
+
+	done = 0;
+	do {
+		len = min(count - done, (size_t) 4096);
+		rc = uaccess.copy_from_user(len, src + done, dst);
+		if (unlikely(rc == len))
+			return -EFAULT;
+		len -= rc;
+		len_str = strnlen(dst, len);
+		done += len_str;
+	} while ((len_str == len) && (done < count));
+	return done;
+}
 
 
 struct uaccess_ops uaccess_mvcos = {
 struct uaccess_ops uaccess_mvcos = {
 	.copy_from_user = copy_from_user_mvcos_check,
 	.copy_from_user = copy_from_user_mvcos_check,
@@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = {
 	.clear_user = clear_user_mvcos,
 	.clear_user = clear_user_mvcos,
 	.strnlen_user = strnlen_user_std,
 	.strnlen_user = strnlen_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
-	.futex_atomic_op = futex_atomic_op,
-	.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+	.futex_atomic_op = futex_atomic_op_std,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
+};
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+struct uaccess_ops uaccess_mvcos_switch = {
+	.copy_from_user = copy_from_user_mvcos,
+	.copy_from_user_small = copy_from_user_mvcos,
+	.copy_to_user = copy_to_user_mvcos,
+	.copy_to_user_small = copy_to_user_mvcos,
+	.copy_in_user = copy_in_user_mvcos,
+	.clear_user = clear_user_mvcos,
+	.strnlen_user = strnlen_user_mvcos,
+	.strncpy_from_user = strncpy_from_user_mvcos,
+	.futex_atomic_op = futex_atomic_op_pt,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
 };
 };
+#endif

+ 324 - 5
arch/s390/lib/uaccess_pt.c

@@ -1,7 +1,8 @@
 /*
 /*
  *  arch/s390/lib/uaccess_pt.c
  *  arch/s390/lib/uaccess_pt.c
  *
  *
- *  User access functions based on page table walks.
+ *  User access functions based on page table walks for enhanced
+ *  system layout without hardware support.
  *
  *
  *    Copyright IBM Corp. 2006
  *    Copyright IBM Corp. 2006
  *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
  *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
@@ -12,9 +13,10 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 
-static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
-				 int write_access)
+static int __handle_fault(struct mm_struct *mm, unsigned long address,
+			  int write_access)
 {
 {
 	struct vm_area_struct *vma;
 	struct vm_area_struct *vma;
 	int ret = -EFAULT;
 	int ret = -EFAULT;
@@ -79,8 +81,8 @@ out_sigbus:
 	return ret;
 	return ret;
 }
 }
 
 
-static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
-				    size_t n, int write_user)
+static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+			     size_t n, int write_user)
 {
 {
 	struct mm_struct *mm = current->mm;
 	struct mm_struct *mm = current->mm;
 	unsigned long offset, pfn, done, size;
 	unsigned long offset, pfn, done, size;
@@ -133,6 +135,49 @@ fault:
 	goto retry;
 	goto retry;
 }
 }
 
 
+/*
+ * Do DAT for user address by page table walk, return kernel address.
+ * This function needs to be called with current->mm->page_table_lock held.
+ */
+static unsigned long __dat_user_addr(unsigned long uaddr)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long pfn, ret;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	int rc;
+
+	ret = 0;
+retry:
+	pgd = pgd_offset(mm, uaddr);
+	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+		goto fault;
+
+	pmd = pmd_offset(pgd, uaddr);
+	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+		goto fault;
+
+	pte = pte_offset_map(pmd, uaddr);
+	if (!pte || !pte_present(*pte))
+		goto fault;
+
+	pfn = pte_pfn(*pte);
+	if (!pfn_valid(pfn))
+		goto out;
+
+	ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+out:
+	return ret;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	rc = __handle_fault(mm, uaddr, 0);
+	spin_lock(&mm->page_table_lock);
+	if (rc)
+		goto out;
+	goto retry;
+}
+
 size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
 size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
 {
 {
 	size_t rc;
 	size_t rc;
@@ -155,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
 	}
 	}
 	return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
 	return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
 }
 }
+
+static size_t clear_user_pt(size_t n, void __user *to)
+{
+	long done, size, ret;
+
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		memset((void __kernel __force *) to, 0, n);
+		return 0;
+	}
+	done = 0;
+	do {
+		if (n - done > PAGE_SIZE)
+			size = PAGE_SIZE;
+		else
+			size = n - done;
+		ret = __user_copy_pt((unsigned long) to + done,
+				      &empty_zero_page, size, 1);
+		done += size;
+		if (ret)
+			return ret + n - done;
+	} while (done < n);
+	return 0;
+}
+
+static size_t strnlen_user_pt(size_t count, const char __user *src)
+{
+	char *addr;
+	unsigned long uaddr = (unsigned long) src;
+	struct mm_struct *mm = current->mm;
+	unsigned long offset, pfn, done, len;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	size_t len_str;
+
+	if (segment_eq(get_fs(), KERNEL_DS))
+		return strnlen((const char __kernel __force *) src, count) + 1;
+	done = 0;
+retry:
+	spin_lock(&mm->page_table_lock);
+	do {
+		pgd = pgd_offset(mm, uaddr);
+		if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+			goto fault;
+
+		pmd = pmd_offset(pgd, uaddr);
+		if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+			goto fault;
+
+		pte = pte_offset_map(pmd, uaddr);
+		if (!pte || !pte_present(*pte))
+			goto fault;
+
+		pfn = pte_pfn(*pte);
+		if (!pfn_valid(pfn)) {
+			done = -1;
+			goto out;
+		}
+
+		offset = uaddr & (PAGE_SIZE-1);
+		addr = (char *)(pfn << PAGE_SHIFT) + offset;
+		len = min(count - done, PAGE_SIZE - offset);
+		len_str = strnlen(addr, len);
+		done += len_str;
+		uaddr += len_str;
+	} while ((len_str == len) && (done < count));
+out:
+	spin_unlock(&mm->page_table_lock);
+	return done + 1;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	if (__handle_fault(mm, uaddr, 0)) {
+		return 0;
+	}
+	goto retry;
+}
+
+static size_t strncpy_from_user_pt(size_t count, const char __user *src,
+				   char *dst)
+{
+	size_t n = strnlen_user_pt(count, src);
+
+	if (!n)
+		return -EFAULT;
+	if (n > count)
+		n = count;
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		memcpy(dst, (const char __kernel __force *) src, n);
+		if (dst[n-1] == '\0')
+			return n-1;
+		else
+			return n;
+	}
+	if (__user_copy_pt((unsigned long) src, dst, n, 0))
+		return -EFAULT;
+	if (dst[n-1] == '\0')
+		return n-1;
+	else
+		return n;
+}
+
+static size_t copy_in_user_pt(size_t n, void __user *to,
+			      const void __user *from)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+		      uaddr, done, size;
+	unsigned long uaddr_from = (unsigned long) from;
+	unsigned long uaddr_to = (unsigned long) to;
+	pgd_t *pgd_from, *pgd_to;
+	pmd_t *pmd_from, *pmd_to;
+	pte_t *pte_from, *pte_to;
+	int write_user;
+
+	done = 0;
+retry:
+	spin_lock(&mm->page_table_lock);
+	do {
+		pgd_from = pgd_offset(mm, uaddr_from);
+		if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pgd_to = pgd_offset(mm, uaddr_to);
+		if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pmd_from = pmd_offset(pgd_from, uaddr_from);
+		if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pmd_to = pmd_offset(pgd_to, uaddr_to);
+		if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pte_from = pte_offset_map(pmd_from, uaddr_from);
+		if (!pte_from || !pte_present(*pte_from)) {
+			uaddr = uaddr_from;
+			write_user = 0;
+			goto fault;
+		}
+		pte_to = pte_offset_map(pmd_to, uaddr_to);
+		if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
+			uaddr = uaddr_to;
+			write_user = 1;
+			goto fault;
+		}
+
+		pfn_from = pte_pfn(*pte_from);
+		if (!pfn_valid(pfn_from))
+			goto out;
+		pfn_to = pte_pfn(*pte_to);
+		if (!pfn_valid(pfn_to))
+			goto out;
+
+		offset_from = uaddr_from & (PAGE_SIZE-1);
+		offset_to = uaddr_from & (PAGE_SIZE-1);
+		offset_max = max(offset_from, offset_to);
+		size = min(n - done, PAGE_SIZE - offset_max);
+
+		memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+		       (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+		done += size;
+		uaddr_from += size;
+		uaddr_to += size;
+	} while (done < n);
+out:
+	spin_unlock(&mm->page_table_lock);
+	return n - done;
+fault:
+	spin_unlock(&mm->page_table_lock);
+	if (__handle_fault(mm, uaddr, write_user))
+		return n - done;
+	goto retry;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)	\
+	asm volatile("0: l   %1,0(%6)\n"				\
+		     "1: " insn						\
+		     "2: cs  %1,%2,0(%6)\n"				\
+		     "3: jl  1b\n"					\
+		     "   lhi %0,0\n"					\
+		     "4:\n"						\
+		     EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)	\
+		     : "=d" (ret), "=&d" (oldval), "=&d" (newval),	\
+		       "=m" (*uaddr)					\
+		     : "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
+		       "m" (*uaddr) : "cc" );
+
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+{
+	int oldval = 0, newval, ret;
+
+	spin_lock(&current->mm->page_table_lock);
+	uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+	if (!uaddr) {
+		spin_unlock(&current->mm->page_table_lock);
+		return -EFAULT;
+	}
+	get_page(virt_to_page(uaddr));
+	spin_unlock(&current->mm->page_table_lock);
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("lr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("lr %2,%1\nar %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("lr %2,%1\nor %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+				  ret, oldval, newval, uaddr, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+	put_page(virt_to_page(uaddr));
+	*old = oldval;
+	return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+	int ret;
+
+	spin_lock(&current->mm->page_table_lock);
+	uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+	if (!uaddr) {
+		spin_unlock(&current->mm->page_table_lock);
+		return -EFAULT;
+	}
+	get_page(virt_to_page(uaddr));
+	spin_unlock(&current->mm->page_table_lock);
+	asm volatile("   cs   %1,%4,0(%5)\n"
+		     "0: lr   %0,%1\n"
+		     "1:\n"
+		     EX_TABLE(0b,1b)
+		     : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+		     : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+		     : "cc", "memory" );
+	put_page(virt_to_page(uaddr));
+	return ret;
+}
+
+struct uaccess_ops uaccess_pt = {
+	.copy_from_user		= copy_from_user_pt,
+	.copy_from_user_small	= copy_from_user_pt,
+	.copy_to_user		= copy_to_user_pt,
+	.copy_to_user_small	= copy_to_user_pt,
+	.copy_in_user		= copy_in_user_pt,
+	.clear_user		= clear_user_pt,
+	.strnlen_user		= strnlen_user_pt,
+	.strncpy_from_user	= strncpy_from_user_pt,
+	.futex_atomic_op	= futex_atomic_op_pt,
+	.futex_atomic_cmpxchg	= futex_atomic_cmpxchg_pt,
+};

+ 12 - 11
arch/s390/lib/uaccess_std.c

@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <asm/futex.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 
 #ifndef __s390x__
 #ifndef __s390x__
 #define AHI	"ahi"
 #define AHI	"ahi"
@@ -28,9 +29,6 @@
 #define SLR	"slgr"
 #define SLR	"slgr"
 #endif
 #endif
 
 
-extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to);
-extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from);
-
 size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
 size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
 {
 {
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
@@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
 	return size;
 	return size;
 }
 }
 
 
-size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
+				       void *x)
 {
 {
 	if (size <= 1024)
 	if (size <= 1024)
 		return copy_from_user_std(size, ptr, x);
 		return copy_from_user_std(size, ptr, x);
@@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
 	return size;
 	return size;
 }
 }
 
 
-size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_std_check(size_t size, void __user *ptr,
+				     const void *x)
 {
 {
 	if (size <= 1024)
 	if (size <= 1024)
 		return copy_to_user_std(size, ptr, x);
 		return copy_to_user_std(size, ptr, x);
 	return copy_to_user_pt(size, ptr, x);
 	return copy_to_user_pt(size, ptr, x);
 }
 }
 
 
-size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_std(size_t size, void __user *to,
+			       const void __user *from)
 {
 {
 	unsigned long tmp1;
 	unsigned long tmp1;
 
 
@@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
 	return size;
 	return size;
 }
 }
 
 
-size_t clear_user_std(size_t size, void __user *to)
+static size_t clear_user_std(size_t size, void __user *to)
 {
 {
 	unsigned long tmp1, tmp2;
 	unsigned long tmp1, tmp2;
 
 
@@ -254,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
 		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
 		  "m" (*uaddr) : "cc");
 		  "m" (*uaddr) : "cc");
 
 
-int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
 {
 {
 	int oldval = 0, newval, ret;
 	int oldval = 0, newval, ret;
 
 
@@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
 	return ret;
 	return ret;
 }
 }
 
 
-int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
 {
 {
 	int ret;
 	int ret;
 
 
@@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = {
 	.clear_user = clear_user_std,
 	.clear_user = clear_user_std,
 	.strnlen_user = strnlen_user_std,
 	.strnlen_user = strnlen_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
 	.strncpy_from_user = strncpy_from_user_std,
-	.futex_atomic_op = futex_atomic_op,
-	.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+	.futex_atomic_op = futex_atomic_op_std,
+	.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 };
 };

+ 1 - 1
arch/s390/math-emu/Makefile

@@ -2,7 +2,7 @@
 # Makefile for the FPU instruction emulation.
 # Makefile for the FPU instruction emulation.
 #
 #
 
 
-obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+obj-$(CONFIG_MATHEMU) := math.o
 
 
 EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
 EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
 EXTRA_AFLAGS := -traditional
 EXTRA_AFLAGS := -traditional

+ 1 - 1
arch/s390/math-emu/math.c

@@ -15,7 +15,7 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
 #include <asm/lowcore.h>
 
 
-#include "sfp-util.h"
+#include <asm/sfp-util.h>
 #include <math-emu/soft-fp.h>
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
 #include <math-emu/double.h>

+ 0 - 77
arch/s390/math-emu/qrnnd.S

@@ -1,77 +0,0 @@
-# S/390 __udiv_qrnnd
-
-# r2 : &__r
-# r3 : upper half of 64 bit word n
-# r4 : lower half of 64 bit word n
-# r5 : divisor d
-# the reminder r of the division is to be stored to &__r and
-# the quotient q is to be returned
-
-        .text
-        .globl __udiv_qrnnd
-__udiv_qrnnd:
-        st    %r2,24(%r15)        # store pointer to reminder for later
-        lr    %r0,%r3             # reload n
-	lr    %r1,%r4
-	ltr   %r2,%r5             # reload and test divisor
-        jp    5f
-        # divisor >= 0x80000000
-	srdl  %r0,2               # n/4
-        srl   %r2,1               # d/2
-        slr   %r1,%r2             # special case if last bit of d is set
-        brc   3,0f                #  (n/4) div (n/2) can overflow by 1
-        ahi   %r0,-1              #  trick: subtract n/2, then divide
-0:      dr    %r0,%r2             # signed division
-        ahi   %r1,1               #  trick part 2: add 1 to the quotient
-        # now (n >> 2) = (d >> 1) * %r1 + %r0
-	lhi   %r3,1
-        nr    %r3,%r1             # test last bit of q
-        jz    1f
-        alr   %r0,%r2             # add (d>>1) to r
-1:      srl   %r1,1               # q >>= 1
-        # now (n >> 2) = (d&-2) * %r1 + %r0
-        lhi   %r3,1
-        nr    %r3,%r5             # test last bit of d
-        jz    2f
-        slr   %r0,%r1             # r -= q
-	brc   3,2f                # borrow ?
-	alr   %r0,%r5             # r += d
-	ahi   %r1,-1
-2:      # now (n >> 2) = d * %r1 + %r0
-        alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,3f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-3:      lhi   %r3,2
-        nr    %r3,%r4             # test next to last bit of n
-        jz    4f
-        ahi   %r0,1               # r += 1
-4:      clr   %r0,%r5             # r >= d ?
-        jl    6f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-        # now (n >> 1) = d * %r1 + %r0
-        j     6f
-5:      # divisor < 0x80000000
-	srdl  %r0,1
-        dr    %r0,%r2             # signed division
-        # now (n >> 1) = d * %r1 + %r0
-6:      alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,7f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-7:      lhi   %r3,1
-        nr    %r3,%r4             # isolate last bit of n
-        alr   %r0,%r3             # r += (n & 1)
-        clr   %r0,%r5             # r >= d ?
-        jl    8f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-8:      # now n = d * %r1 + %r0
-	l     %r2,24(%r15)
-        st    %r0,0(%r2)
-        lr    %r2,%r1
-        br    %r14
-	.end	__udiv_qrnnd

+ 2 - 2
arch/s390/mm/cmm.c

@@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds)
 	cmm_set_timer();
 	cmm_set_timer();
 }
 }
 
 
-static inline int
+static int
 cmm_skip_blanks(char *cp, char **endp)
 cmm_skip_blanks(char *cp, char **endp)
 {
 {
 	char *str;
 	char *str;
@@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg)
 }
 }
 #endif
 #endif
 
 
-struct ctl_table_header *cmm_sysctl_header;
+static struct ctl_table_header *cmm_sysctl_header;
 
 
 static int
 static int
 cmm_init (void)
 cmm_init (void)

+ 55 - 11
arch/s390/mm/extmem.c

@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/bootmem.h>
 #include <linux/ctype.h>
 #include <linux/ctype.h>
+#include <linux/ioport.h>
 #include <asm/page.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable.h>
 #include <asm/ebcdic.h>
 #include <asm/ebcdic.h>
@@ -70,6 +71,7 @@ struct qin64 {
 struct dcss_segment {
 struct dcss_segment {
 	struct list_head list;
 	struct list_head list;
 	char dcss_name[8];
 	char dcss_name[8];
+	char res_name[15];
 	unsigned long start_addr;
 	unsigned long start_addr;
 	unsigned long end;
 	unsigned long end;
 	atomic_t ref_count;
 	atomic_t ref_count;
@@ -77,6 +79,7 @@ struct dcss_segment {
 	unsigned int vm_segtype;
 	unsigned int vm_segtype;
 	struct qrange range[6];
 	struct qrange range[6];
 	int segcnt;
 	int segcnt;
+	struct resource *res;
 };
 };
 
 
 static DEFINE_MUTEX(dcss_lock);
 static DEFINE_MUTEX(dcss_lock);
@@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
  * Create the 8 bytes, ebcdic VM segment name from
  * Create the 8 bytes, ebcdic VM segment name from
  * an ascii name.
  * an ascii name.
  */
  */
-static void inline
+static void
 dcss_mkname(char *name, char *dcss_name)
 dcss_mkname(char *name, char *dcss_name)
 {
 {
 	int i;
 	int i;
@@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 		goto out_free;
 		goto out_free;
 	}
 	}
 
 
+	seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+	if (seg->res == NULL) {
+		rc = -ENOMEM;
+		goto out_shared;
+	}
+	seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+	seg->res->start = seg->start_addr;
+	seg->res->end = seg->end;
+	memcpy(&seg->res_name, seg->dcss_name, 8);
+	EBCASC(seg->res_name, 8);
+	seg->res_name[8] = '\0';
+	strncat(seg->res_name, " (DCSS)", 7);
+	seg->res->name = seg->res_name;
+	rc = seg->vm_segtype;
+	if (rc == SEG_TYPE_SC ||
+	    ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
+		seg->res->flags |= IORESOURCE_READONLY;
+	if (request_resource(&iomem_resource, seg->res)) {
+		rc = -EBUSY;
+		kfree(seg->res);
+		goto out_shared;
+	}
+
 	if (do_nonshared)
 	if (do_nonshared)
 		dcss_command = DCSS_LOADNSR;
 		dcss_command = DCSS_LOADNSR;
 	else
 	else
@@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 		rc = dcss_diag_translate_rc (seg->end);
 		rc = dcss_diag_translate_rc (seg->end);
 		dcss_diag(DCSS_PURGESEG, seg->dcss_name,
 		dcss_diag(DCSS_PURGESEG, seg->dcss_name,
 				&seg->start_addr, &seg->end);
 				&seg->start_addr, &seg->end);
-		goto out_shared;
+		goto out_resource;
 	}
 	}
 	seg->do_nonshared = do_nonshared;
 	seg->do_nonshared = do_nonshared;
 	atomic_set(&seg->ref_count, 1);
 	atomic_set(&seg->ref_count, 1);
 	list_add(&seg->list, &dcss_list);
 	list_add(&seg->list, &dcss_list);
-	rc = seg->vm_segtype;
 	*addr = seg->start_addr;
 	*addr = seg->start_addr;
 	*end  = seg->end;
 	*end  = seg->end;
 	if (do_nonshared)
 	if (do_nonshared)
@@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
 				"type %s in non-shared mode\n", name,
 				"type %s in non-shared mode\n", name,
 				(void*)seg->start_addr, (void*)seg->end,
 				(void*)seg->start_addr, (void*)seg->end,
 				segtype_string[seg->vm_segtype]);
 				segtype_string[seg->vm_segtype]);
-	else
+	else {
 		PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
 		PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
 				"type %s in shared mode\n", name,
 				"type %s in shared mode\n", name,
 				(void*)seg->start_addr, (void*)seg->end,
 				(void*)seg->start_addr, (void*)seg->end,
 				segtype_string[seg->vm_segtype]);
 				segtype_string[seg->vm_segtype]);
+	}
 	goto out;
 	goto out;
+ out_resource:
+	release_resource(seg->res);
+	kfree(seg->res);
  out_shared:
  out_shared:
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
  out_free:
  out_free:
@@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
  * -ENOENT  : no such segment (segment gone!)
  * -ENOENT  : no such segment (segment gone!)
  * -EAGAIN  : segment is in use by other exploiters, try later
  * -EAGAIN  : segment is in use by other exploiters, try later
  * -EINVAL  : no segment with the given name is currently loaded - name invalid
  * -EINVAL  : no segment with the given name is currently loaded - name invalid
+ * -EBUSY   : segment can temporarily not be used (overlaps with dcss)
  * 0	    : operation succeeded
  * 0	    : operation succeeded
  */
  */
 int
 int
@@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
 		rc = -EAGAIN;
 		rc = -EAGAIN;
 		goto out_unlock;
 		goto out_unlock;
 	}
 	}
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-		  &dummy, &dummy);
-	if (do_nonshared)
+	release_resource(seg->res);
+	if (do_nonshared) {
 		dcss_command = DCSS_LOADNSR;
 		dcss_command = DCSS_LOADNSR;
-	else
-	dcss_command = DCSS_LOADNOLY;
+		seg->res->flags &= ~IORESOURCE_READONLY;
+	} else {
+		dcss_command = DCSS_LOADNOLY;
+		if (seg->vm_segtype == SEG_TYPE_SR ||
+		    seg->vm_segtype == SEG_TYPE_ER)
+			seg->res->flags |= IORESOURCE_READONLY;
+	}
+	if (request_resource(&iomem_resource, seg->res)) {
+		PRINT_WARN("segment_modify_shared: could not reload segment %s"
+			   " - overlapping resources\n", name);
+		rc = -EBUSY;
+		kfree(seg->res);
+		goto out_del;
+	}
+	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
 	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
 	diag_cc = dcss_diag(dcss_command, seg->dcss_name,
 			&seg->start_addr, &seg->end);
 			&seg->start_addr, &seg->end);
 	if (diag_cc > 1) {
 	if (diag_cc > 1) {
@@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
 	rc = 0;
 	rc = 0;
 	goto out_unlock;
 	goto out_unlock;
  out_del:
  out_del:
+	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
 	list_del(&seg->list);
-	dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-		  &dummy, &dummy);
+	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
 	kfree(seg);
 	kfree(seg);
  out_unlock:
  out_unlock:
 	mutex_unlock(&dcss_lock);
 	mutex_unlock(&dcss_lock);
@@ -478,6 +520,8 @@ segment_unload(char *name)
 	}
 	}
 	if (atomic_dec_return(&seg->ref_count) != 0)
 	if (atomic_dec_return(&seg->ref_count) != 0)
 		goto out_unlock;
 		goto out_unlock;
+	release_resource(seg->res);
+	kfree(seg->res);
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
 	list_del(&seg->list);
 	list_del(&seg->list);
 	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
 	dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);

+ 88 - 5
arch/s390/mm/fault.c

@@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug;
 extern void die(const char *,struct pt_regs *,long);
 extern void die(const char *,struct pt_regs *,long);
 
 
 #ifdef CONFIG_KPROBES
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
 int register_page_fault_notifier(struct notifier_block *nb)
 int register_page_fault_notifier(struct notifier_block *nb)
 {
 {
 	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
 	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
@@ -137,7 +137,9 @@ static int __check_access_register(struct pt_regs *regs, int error_code)
 
 
 /*
 /*
  * Check which address space the address belongs to.
  * Check which address space the address belongs to.
- * Returns 1 for user space and 0 for kernel space.
+ * May return 1 or 2 for user space and 0 for kernel space.
+ * Returns 2 for user space in primary addressing mode with
+ * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
  */
  */
 static inline int check_user_space(struct pt_regs *regs, int error_code)
 static inline int check_user_space(struct pt_regs *regs, int error_code)
 {
 {
@@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
 		return __check_access_register(regs, error_code);
 		return __check_access_register(regs, error_code);
 	if (descriptor == 2)
 	if (descriptor == 2)
 		return current->thread.mm_segment.ar4;
 		return current->thread.mm_segment.ar4;
-	return descriptor != 0;
+	return ((descriptor != 0) ^ (switch_amode)) << s390_noexec;
 }
 }
 
 
 /*
 /*
@@ -183,6 +185,77 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
 	force_sig_info(SIGSEGV, &si, current);
 	force_sig_info(SIGSEGV, &si, current);
 }
 }
 
 
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern long sys_sigreturn(struct pt_regs *regs);
+extern long sys_rt_sigreturn(struct pt_regs *regs);
+extern long sys32_sigreturn(struct pt_regs *regs);
+extern long sys32_rt_sigreturn(struct pt_regs *regs);
+
+static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
+				int rt)
+{
+	up_read(&mm->mmap_sem);
+	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+#ifdef CONFIG_COMPAT
+	if (test_tsk_thread_flag(current, TIF_31BIT)) {
+		if (rt)
+			sys32_rt_sigreturn(regs);
+		else
+			sys32_sigreturn(regs);
+		return;
+	}
+#endif /* CONFIG_COMPAT */
+	if (rt)
+		sys_rt_sigreturn(regs);
+	else
+		sys_sigreturn(regs);
+	return;
+}
+
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+			 unsigned long address, unsigned long error_code)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	u16 *instruction;
+	unsigned long pfn, uaddr = regs->psw.addr;
+
+	spin_lock(&mm->page_table_lock);
+	pgd = pgd_offset(mm, uaddr);
+	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+		goto out_fault;
+	pmd = pmd_offset(pgd, uaddr);
+	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+		goto out_fault;
+	pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
+	if (!pte || !pte_present(*pte))
+		goto out_fault;
+	pfn = pte_pfn(*pte);
+	if (!pfn_valid(pfn))
+		goto out_fault;
+	spin_unlock(&mm->page_table_lock);
+
+	instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
+	if (*instruction == 0x0a77)
+		do_sigreturn(mm, regs, 0);
+	else if (*instruction == 0x0aad)
+		do_sigreturn(mm, regs, 1);
+	else {
+		printk("- XXX - do_exception: task = %s, primary, NO EXEC "
+		       "-> SIGSEGV\n", current->comm);
+		up_read(&mm->mmap_sem);
+		current->thread.prot_addr = address;
+		current->thread.trap_no = error_code;
+		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+	}
+	return 0;
+out_fault:
+	spin_unlock(&mm->page_table_lock);
+	return -EFAULT;
+}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
 /*
 /*
  * This routine handles page faults.  It determines the address,
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * and the problem, and then passes it off to one of the appropriate
@@ -260,6 +333,17 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
         vma = find_vma(mm, address);
         vma = find_vma(mm, address);
         if (!vma)
         if (!vma)
                 goto bad_area;
                 goto bad_area;
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+	if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC)))
+		if (!signal_return(mm, regs, address, error_code))
+			/*
+			 * signal_return() has done an up_read(&mm->mmap_sem)
+			 * if it returns 0.
+			 */
+			return;
+#endif
+
         if (vma->vm_start <= address) 
         if (vma->vm_start <= address) 
                 goto good_area;
                 goto good_area;
         if (!(vma->vm_flags & VM_GROWSDOWN))
         if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -452,8 +536,7 @@ void pfault_fini(void)
 		: : "a" (&refbk), "m" (refbk) : "cc");
 		: : "a" (&refbk), "m" (refbk) : "cc");
 }
 }
 
 
-asmlinkage void
-pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 error_code)
 {
 {
 	struct task_struct *tsk;
 	struct task_struct *tsk;
 	__u16 subcode;
 	__u16 subcode;

+ 8 - 12
arch/s390/mm/init.c

@@ -25,7 +25,7 @@
 #include <linux/bootmem.h>
 #include <linux/bootmem.h>
 #include <linux/pfn.h>
 #include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/poison.h>
-
+#include <linux/initrd.h>
 #include <asm/processor.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
@@ -95,20 +95,18 @@ static void __init setup_ro_region(void)
 	pte_t new_pte;
 	pte_t new_pte;
 	unsigned long address, end;
 	unsigned long address, end;
 
 
-	address = ((unsigned long)&__start_rodata) & PAGE_MASK;
-	end = PFN_ALIGN((unsigned long)&__end_rodata);
+	address = ((unsigned long)&_stext) & PAGE_MASK;
+	end = PFN_ALIGN((unsigned long)&_eshared);
 
 
 	for (; address < end; address += PAGE_SIZE) {
 	for (; address < end; address += PAGE_SIZE) {
 		pgd = pgd_offset_k(address);
 		pgd = pgd_offset_k(address);
 		pmd = pmd_offset(pgd, address);
 		pmd = pmd_offset(pgd, address);
 		pte = pte_offset_kernel(pmd, address);
 		pte = pte_offset_kernel(pmd, address);
 		new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
 		new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
-		set_pte(pte, new_pte);
+		*pte = new_pte;
 	}
 	}
 }
 }
 
 
-extern void vmem_map_init(void);
-
 /*
 /*
  * paging_init() sets up the page tables
  * paging_init() sets up the page tables
  */
  */
@@ -125,11 +123,11 @@ void __init paging_init(void)
 #ifdef CONFIG_64BIT
 #ifdef CONFIG_64BIT
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
 	for (i = 0; i < PTRS_PER_PGD; i++)
 	for (i = 0; i < PTRS_PER_PGD; i++)
-		pgd_clear(pg_dir + i);
+		pgd_clear_kernel(pg_dir + i);
 #else
 #else
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
 	pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
 	for (i = 0; i < PTRS_PER_PGD; i++)
 	for (i = 0; i < PTRS_PER_PGD; i++)
-		pmd_clear((pmd_t *)(pg_dir + i));
+		pmd_clear_kernel((pmd_t *)(pg_dir + i));
 #endif
 #endif
 	vmem_map_init();
 	vmem_map_init();
 	setup_ro_region();
 	setup_ro_region();
@@ -174,10 +172,8 @@ void __init mem_init(void)
                 datasize >>10,
                 datasize >>10,
                 initsize >> 10);
                 initsize >> 10);
 	printk("Write protected kernel read-only data: %#lx - %#lx\n",
 	printk("Write protected kernel read-only data: %#lx - %#lx\n",
-	       (unsigned long)&__start_rodata,
-	       PFN_ALIGN((unsigned long)&__end_rodata) - 1);
-	printk("Virtual memmap size: %ldk\n",
-	       (max_pfn * sizeof(struct page)) >> 10);
+	       (unsigned long)&_stext,
+	       PFN_ALIGN((unsigned long)&_eshared) - 1);
 }
 }
 
 
 void free_initmem(void)
 void free_initmem(void)

+ 7 - 7
arch/s390/mm/vmem.c

@@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void)
 	if (!pmd)
 	if (!pmd)
 		return NULL;
 		return NULL;
 	for (i = 0; i < PTRS_PER_PMD; i++)
 	for (i = 0; i < PTRS_PER_PMD; i++)
-		pmd_clear(pmd + i);
+		pmd_clear_kernel(pmd + i);
 	return pmd;
 	return pmd;
 }
 }
 
 
@@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void)
 		return NULL;
 		return NULL;
 	pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
 	pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
 	for (i = 0; i < PTRS_PER_PTE; i++)
 	for (i = 0; i < PTRS_PER_PTE; i++)
-		set_pte(pte + i, empty_pte);
+		pte[i] = empty_pte;
 	return pte;
 	return pte;
 }
 }
 
 
@@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
 			pm_dir = vmem_pmd_alloc();
 			pm_dir = vmem_pmd_alloc();
 			if (!pm_dir)
 			if (!pm_dir)
 				goto out;
 				goto out;
-			pgd_populate(&init_mm, pg_dir, pm_dir);
+			pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
 		}
 		}
 
 
 		pm_dir = pmd_offset(pg_dir, address);
 		pm_dir = pmd_offset(pg_dir, address);
@@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
 
 
 		pt_dir = pte_offset_kernel(pm_dir, address);
 		pt_dir = pte_offset_kernel(pm_dir, address);
 		pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
 		pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
-		set_pte(pt_dir, pte);
+		*pt_dir = pte;
 	}
 	}
 	ret = 0;
 	ret = 0;
 out:
 out:
@@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
 		if (pmd_none(*pm_dir))
 		if (pmd_none(*pm_dir))
 			continue;
 			continue;
 		pt_dir = pte_offset_kernel(pm_dir, address);
 		pt_dir = pte_offset_kernel(pm_dir, address);
-		set_pte(pt_dir, pte);
+		*pt_dir = pte;
 	}
 	}
 	flush_tlb_kernel_range(start, start + size);
 	flush_tlb_kernel_range(start, start + size);
 }
 }
@@ -191,7 +191,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
 			pm_dir = vmem_pmd_alloc();
 			pm_dir = vmem_pmd_alloc();
 			if (!pm_dir)
 			if (!pm_dir)
 				goto out;
 				goto out;
-			pgd_populate(&init_mm, pg_dir, pm_dir);
+			pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
 		}
 		}
 
 
 		pm_dir = pmd_offset(pg_dir, address);
 		pm_dir = pmd_offset(pg_dir, address);
@@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
 			if (!new_page)
 			if (!new_page)
 				goto out;
 				goto out;
 			pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
 			pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
-			set_pte(pt_dir, pte);
+			*pt_dir = pte;
 		}
 		}
 	}
 	}
 	ret = 0;
 	ret = 0;

+ 0 - 49
crypto/Kconfig

@@ -74,14 +74,6 @@ config CRYPTO_SHA1
 	help
 	help
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
 
-config CRYPTO_SHA1_S390
-	tristate "SHA1 digest algorithm (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
 config CRYPTO_SHA256
 config CRYPTO_SHA256
 	tristate "SHA256 digest algorithm"
 	tristate "SHA256 digest algorithm"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -91,17 +83,6 @@ config CRYPTO_SHA256
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  security against collision attacks.
 	  security against collision attacks.
 
 
-config CRYPTO_SHA256_S390
-	tristate "SHA256 digest algorithm (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA256 secure hash standard (DFIPS 180-2).
-
-	  This version of SHA implements a 256 bit hash with 128 bits of
-	  security against collision attacks.
-
 config CRYPTO_SHA512
 config CRYPTO_SHA512
 	tristate "SHA384 and SHA512 digest algorithms"
 	tristate "SHA384 and SHA512 digest algorithms"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -187,14 +168,6 @@ config CRYPTO_DES
 	help
 	help
 	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
 	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
 
 
-config CRYPTO_DES_S390
-	tristate "DES and Triple DES cipher algorithms (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	select CRYPTO_BLKCIPHER
-	help
-	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
 config CRYPTO_BLOWFISH
 config CRYPTO_BLOWFISH
 	tristate "Blowfish cipher algorithm"
 	tristate "Blowfish cipher algorithm"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -336,28 +309,6 @@ config CRYPTO_AES_X86_64
 
 
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 	  See <http://csrc.nist.gov/encryption/aes/> for more information.
 
 
-config CRYPTO_AES_S390
-	tristate "AES cipher algorithms (s390)"
-	depends on S390
-	select CRYPTO_ALGAPI
-	select CRYPTO_BLKCIPHER
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
-	  algorithm.
-
-	  Rijndael appears to be consistently a very good performer in
-	  both hardware and software across a wide range of computing
-	  environments regardless of its use in feedback or non-feedback
-	  modes. Its key setup time is excellent, and its key agility is
-	  good. Rijndael's very low memory requirements make it very well
-	  suited for restricted-space environments, in which it also
-	  demonstrates excellent performance. Rijndael's operations are
-	  among the easiest to defend against power and timing attacks.
-
-	  On s390 the System z9-109 currently only supports the key size
-	  of 128 bit.
-
 config CRYPTO_CAST5
 config CRYPTO_CAST5
 	tristate "CAST5 (CAST-128) cipher algorithm"
 	tristate "CAST5 (CAST-128) cipher algorithm"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI

+ 2 - 0
drivers/crypto/Kconfig

@@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
 	  If unsure say M. The compiled module will be
 	  If unsure say M. The compiled module will be
 	  called padlock-sha.ko
 	  called padlock-sha.ko
 
 
+source "arch/s390/crypto/Kconfig"
+
 config CRYPTO_DEV_GEODE
 config CRYPTO_DEV_GEODE
 	tristate "Support for the Geode LX AES engine"
 	tristate "Support for the Geode LX AES engine"
 	depends on CRYPTO && X86_32 && PCI
 	depends on CRYPTO && X86_32 && PCI

+ 0 - 8
drivers/s390/Kconfig

@@ -103,14 +103,8 @@ config CCW_CONSOLE
  	depends on TN3215_CONSOLE || TN3270_CONSOLE
  	depends on TN3215_CONSOLE || TN3270_CONSOLE
  	default y
  	default y
  
  
-config SCLP
-	bool "Support for SCLP"
-	help
-	  Include support for the SCLP interface to the service element.
-
 config SCLP_TTY
 config SCLP_TTY
 	bool "Support for SCLP line mode terminal"
 	bool "Support for SCLP line mode terminal"
-	depends on SCLP
 	help
 	help
 	  Include support for IBM SCLP line-mode terminals.
 	  Include support for IBM SCLP line-mode terminals.
 
 
@@ -123,7 +117,6 @@ config SCLP_CONSOLE
 
 
 config SCLP_VT220_TTY
 config SCLP_VT220_TTY
 	bool "Support for SCLP VT220-compatible terminal"
 	bool "Support for SCLP VT220-compatible terminal"
-	depends on SCLP
 	help
 	help
 	  Include support for an IBM SCLP VT220-compatible terminal.
 	  Include support for an IBM SCLP VT220-compatible terminal.
 
 
@@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
 
 
 config SCLP_CPI
 config SCLP_CPI
 	tristate "Control-Program Identification"
 	tristate "Control-Program Identification"
-	depends on SCLP
 	help
 	help
 	  This option enables the hardware console interface for system
 	  This option enables the hardware console interface for system
 	  identification. This is commonly used for workload management and
 	  identification. This is commonly used for workload management and

+ 2 - 0
drivers/s390/Makefile

@@ -2,6 +2,8 @@
 # Makefile for the S/390 specific device drivers
 # Makefile for the S/390 specific device drivers
 #
 #
 
 
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
 obj-y += s390mach.o sysinfo.o s390_rdev.o
 obj-y += s390mach.o sysinfo.o s390_rdev.o
 obj-y += cio/ block/ char/ crypto/ net/ scsi/
 obj-y += cio/ block/ char/ crypto/ net/ scsi/
 
 

+ 23 - 10
drivers/s390/block/dasd.c

@@ -37,6 +37,7 @@
  */
  */
 debug_info_t *dasd_debug_area;
 debug_info_t *dasd_debug_area;
 struct dasd_discipline *dasd_diag_discipline_pointer;
 struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 
 
 MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@ static int  dasd_alloc_queue(struct dasd_device * device);
 static void dasd_setup_queue(struct dasd_device * device);
 static void dasd_setup_queue(struct dasd_device * device);
 static void dasd_free_queue(struct dasd_device * device);
 static void dasd_free_queue(struct dasd_device * device);
 static void dasd_flush_request_queue(struct dasd_device *);
 static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 static int dasd_flush_ccw_queue(struct dasd_device *, int);
 static int dasd_flush_ccw_queue(struct dasd_device *, int);
 static void dasd_tasklet(struct dasd_device *);
 static void dasd_tasklet(struct dasd_device *);
 static void do_kick_device(struct work_struct *);
 static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
 /*
 /*
  * Add profiling information for cqr before execution.
  * Add profiling information for cqr before execution.
  */
  */
-static inline void
+static void
 dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 		   struct request *req)
 		   struct request *req)
 {
 {
@@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 /*
 /*
  * Add profiling information for cqr after execution.
  * Add profiling information for cqr after execution.
  */
  */
-static inline void
+static void
 dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
 dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
 		 struct request *req)
 		 struct request *req)
 {
 {
@@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 		 irb->scsw.cstat == 0 &&
 		 irb->scsw.cstat == 0 &&
 		 !irb->esw.esw0.erw.cons)
 		 !irb->esw.esw0.erw.cons)
 		era = dasd_era_none;
 		era = dasd_era_none;
-	else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
- 	        era = dasd_era_fatal; /* don't recover this request */
 	else if (irb->esw.esw0.erw.cons)
 	else if (irb->esw.esw0.erw.cons)
 		era = device->discipline->examine_error(cqr, irb);
 		era = device->discipline->examine_error(cqr, irb);
 	else
 	else
@@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
 /*
 /*
  * Process ccw request queue.
  * Process ccw request queue.
  */
  */
-static inline void
+static void
 __dasd_process_ccw_queue(struct dasd_device * device,
 __dasd_process_ccw_queue(struct dasd_device * device,
 			 struct list_head *final_queue)
 			 struct list_head *final_queue)
 {
 {
@@ -1127,7 +1125,9 @@ restart:
 				cqr->status = DASD_CQR_FAILED;
 				cqr->status = DASD_CQR_FAILED;
 				cqr->stopclk = get_clock();
 				cqr->stopclk = get_clock();
 			} else {
 			} else {
-				if (cqr->irb.esw.esw0.erw.cons) {
+				if (cqr->irb.esw.esw0.erw.cons &&
+				    test_bit(DASD_CQR_FLAGS_USE_ERP,
+					     &cqr->flags)) {
 					erp_fn = device->discipline->
 					erp_fn = device->discipline->
 						erp_action(cqr);
 						erp_action(cqr);
 					erp_fn(cqr);
 					erp_fn(cqr);
@@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
 /*
 /*
  * Fetch requests from the block device queue.
  * Fetch requests from the block device queue.
  */
  */
-static inline void
+static void
 __dasd_process_blk_queue(struct dasd_device * device)
 __dasd_process_blk_queue(struct dasd_device * device)
 {
 {
 	request_queue_t *queue;
 	request_queue_t *queue;
@@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
 		if (IS_ERR(cqr)) {
 		if (IS_ERR(cqr)) {
 			if (PTR_ERR(cqr) == -ENOMEM)
 			if (PTR_ERR(cqr) == -ENOMEM)
 				break;	/* terminate request queue loop */
 				break;	/* terminate request queue loop */
+			if (PTR_ERR(cqr) == -EAGAIN) {
+				/*
+				 * The current request cannot be build right
+				 * now, we have to try later. If this request
+				 * is the head-of-queue we stop the device
+				 * for 1/2 second.
+				 */
+				if (!list_empty(&device->ccw_queue))
+					break;
+				device->stopped |= DASD_STOPPED_PENDING;
+				dasd_set_timer(device, HZ/2);
+				break;
+			}
 			DBF_DEV_EVENT(DBF_ERR, device,
 			DBF_DEV_EVENT(DBF_ERR, device,
 				      "CCW creation failed (rc=%ld) "
 				      "CCW creation failed (rc=%ld) "
 				      "on request %p",
 				      "on request %p",
@@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  * if it reached its expire time. If so, terminate the IO.
  */
  */
-static inline void
+static void
 __dasd_check_expire(struct dasd_device * device)
 __dasd_check_expire(struct dasd_device * device)
 {
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  * if it needs to be started.
  */
  */
-static inline void
+static void
 __dasd_start_head(struct dasd_device * device)
 __dasd_start_head(struct dasd_device * device)
 {
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *cqr;

+ 0 - 5
drivers/s390/block/dasd_3990_erp.c

@@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
 	/* log the erp chain if fatal error occurred */
 	/* log the erp chain if fatal error occurred */
 	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
 	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
 		dasd_log_sense(cqr, irb);
 		dasd_log_sense(cqr, irb);
-		dasd_log_ccw(cqr, 0, irb->scsw.cpa);
 	}
 	}
 
 
 	return era;
 	return era;
@@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 
 
 	struct dasd_ccw_req *erp = NULL;
 	struct dasd_ccw_req *erp = NULL;
 	struct dasd_device *device = cqr->device;
 	struct dasd_device *device = cqr->device;
-	__u32 cpa = cqr->irb.scsw.cpa;
 	struct dasd_ccw_req *temp_erp = NULL;
 	struct dasd_ccw_req *temp_erp = NULL;
 
 
 	if (device->features & DASD_FEATURE_ERPLOG) {
 	if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 		}
 		}
 	}
 	}
 
 
-	if (erp->status == DASD_CQR_FAILED)
-		dasd_log_ccw(erp, 1, cpa);
-
 	/* enqueue added ERP request */
 	/* enqueue added ERP request */
 	if (erp->status == DASD_CQR_FILLED) {
 	if (erp->status == DASD_CQR_FILLED) {
 		erp->status = DASD_CQR_QUEUED;
 		erp->status = DASD_CQR_QUEUED;

+ 3 - 3
drivers/s390/block/dasd_devmap.c

@@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
 /*
 /*
  * Read a device busid/devno from a string.
  * Read a device busid/devno from a string.
  */
  */
-static inline int
+static int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
 {
 	int val, old_style;
 	int val, old_style;
@@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
  * only one: "ro" for read-only devices. The default feature set
  * only one: "ro" for read-only devices. The default feature set
  * is empty (value 0).
  * is empty (value 0).
  */
  */
-static inline int
+static int
 dasd_feature_list(char *str, char **endp)
 dasd_feature_list(char *str, char **endp)
 {
 {
 	int features, len, rc;
 	int features, len, rc;
@@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
 	return ERR_PTR(-EINVAL);
 	return ERR_PTR(-EINVAL);
 }
 }
 
 
-static inline char *
+static char *
 dasd_parse_next_element( char *parsestring ) {
 dasd_parse_next_element( char *parsestring ) {
 	char * residual_str;
 	char * residual_str;
 	residual_str = dasd_parse_keyword(parsestring);
 	residual_str = dasd_parse_keyword(parsestring);

+ 4 - 4
drivers/s390/block/dasd_diag.c

@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
 #define DIAG_MAX_RETRIES	32
 #define DIAG_MAX_RETRIES	32
 #define DIAG_TIMEOUT		50 * HZ
 #define DIAG_TIMEOUT		50 * HZ
 
 
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
 
 
 struct dasd_diag_private {
 struct dasd_diag_private {
 	struct dasd_diag_characteristics rdc_data;
 	struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
  * block offset. On success, return zero and set end_block to contain the
  * block offset. On success, return zero and set end_block to contain the
  * number of blocks on the device minus the specified offset. Return non-zero
  * number of blocks on the device minus the specified offset. Return non-zero
  * otherwise. */
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
 mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
 	     blocknum_t offset, blocknum_t *end_block)
 	     blocknum_t offset, blocknum_t *end_block)
 {
 {
@@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
 
 
 /* Remove block I/O environment for device. Return zero on success, non-zero
 /* Remove block I/O environment for device. Return zero on success, non-zero
  * otherwise. */
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_term_io(struct dasd_device * device)
 mdsk_term_io(struct dasd_device * device)
 {
 {
 	struct dasd_diag_private *private;
 	struct dasd_diag_private *private;
@@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 		    "dump sense not available for DIAG data");
 		    "dump sense not available for DIAG data");
 }
 }
 
 
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
 	.name = "DIAG",
 	.name = "DIAG",
 	.ebcname = "DIAG",
 	.ebcname = "DIAG",

+ 33 - 62
drivers/s390/block/dasd_eckd.c

@@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
 	return (d1 + (d2 - 1)) / d2;
 	return (d1 + (d2 - 1)) / d2;
 }
 }
 
 
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
-	unsigned int fl1, fl2, int1, int2;
-	int bpr;
-
-	switch (rdc->formula) {
-	case 0x01:
-		fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
-		fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
-					ECKD_F1(rdc));
-		bpr = fl1 + fl2;
-		break;
-	case 0x02:
-		int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-		int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-		fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
-					ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
-					ECKD_F1(rdc));
-		fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
-					ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
-					ECKD_F1(rdc));
-		bpr = fl1 + fl2;
-		break;
-	default:
-		bpr = 0;
-		break;
-	}
-	return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
-	return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
 recs_per_track(struct dasd_eckd_characteristics * rdc,
 recs_per_track(struct dasd_eckd_characteristics * rdc,
 	       unsigned int kl, unsigned int dl)
 	       unsigned int kl, unsigned int dl)
 {
 {
@@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void
+static int
 check_XRC (struct ccw1         *de_ccw,
 check_XRC (struct ccw1         *de_ccw,
            struct DE_eckd_data *data,
            struct DE_eckd_data *data,
            struct dasd_device  *device)
            struct dasd_device  *device)
 {
 {
         struct dasd_eckd_private *private;
         struct dasd_eckd_private *private;
+	int rc;
 
 
         private = (struct dasd_eckd_private *) device->private;
         private = (struct dasd_eckd_private *) device->private;
+	if (!private->rdc_data.facilities.XRC_supported)
+		return 0;
 
 
         /* switch on System Time Stamp - needed for XRC Support */
         /* switch on System Time Stamp - needed for XRC Support */
-        if (private->rdc_data.facilities.XRC_supported) {
-
-                data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
-                data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
-                data->ep_sys_time = get_clock ();
-
-                de_ccw->count = sizeof (struct DE_eckd_data);
-		de_ccw->flags |= CCW_FLAG_SLI;
-        }
+	data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
+	data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
 
 
-        return;
+	rc = get_sync_clock(&data->ep_sys_time);
+	/* Ignore return code if sync clock is switched off. */
+	if (rc == -ENOSYS || rc == -EACCES)
+		rc = 0;
 
 
-} /* end check_XRC */
+	de_ccw->count = sizeof (struct DE_eckd_data);
+	de_ccw->flags |= CCW_FLAG_SLI;
+	return rc;
+}
 
 
-static inline void
+static int
 define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	      int totrk, int cmd, struct dasd_device * device)
 	      int totrk, int cmd, struct dasd_device * device)
 {
 {
 	struct dasd_eckd_private *private;
 	struct dasd_eckd_private *private;
 	struct ch_t geo, beg, end;
 	struct ch_t geo, beg, end;
+	int rc = 0;
 
 
 	private = (struct dasd_eckd_private *) device->private;
 	private = (struct dasd_eckd_private *) device->private;
 
 
@@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	case DASD_ECKD_CCW_WRITE_KD_MT:
 	case DASD_ECKD_CCW_WRITE_KD_MT:
 		data->mask.perm = 0x02;
 		data->mask.perm = 0x02;
 		data->attributes.operation = private->attrib.operation;
 		data->attributes.operation = private->attrib.operation;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 		break;
 	case DASD_ECKD_CCW_WRITE_CKD:
 	case DASD_ECKD_CCW_WRITE_CKD:
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
 		data->attributes.operation = DASD_BYPASS_CACHE;
 		data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 		break;
 	case DASD_ECKD_CCW_ERASE:
 	case DASD_ECKD_CCW_ERASE:
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 		data->mask.perm = 0x3;
 		data->mask.perm = 0x3;
 		data->mask.auth = 0x1;
 		data->mask.auth = 0x1;
 		data->attributes.operation = DASD_BYPASS_CACHE;
 		data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+		rc = check_XRC (ccw, data, device);
 		break;
 		break;
 	default:
 	default:
 		DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
 		DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	data->beg_ext.head = beg.head;
 	data->beg_ext.head = beg.head;
 	data->end_ext.cyl = end.cyl;
 	data->end_ext.cyl = end.cyl;
 	data->end_ext.head = end.head;
 	data->end_ext.head = end.head;
+	return rc;
 }
 }
 
 
-static inline void
+static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 	      int rec_on_trk, int no_rec, int cmd,
 	      int rec_on_trk, int no_rec, int cmd,
 	      struct dasd_device * device, int reclen)
 	      struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
 /*
 /*
  * Build CP for Perform Subsystem Function - SSC.
  * Build CP for Perform Subsystem Function - SSC.
  */
  */
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
 dasd_eckd_build_psf_ssc(struct dasd_device *device)
 dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
 {
        struct dasd_ccw_req *cqr;
        struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 		return cqr;
 		return cqr;
 	ccw = cqr->cpaddr;
 	ccw = cqr->cpaddr;
 	/* First ccw is define extent. */
 	/* First ccw is define extent. */
-	define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+	if (define_extent(ccw++, cqr->data, first_trk,
+			  last_trk, cmd, device) == -EAGAIN) {
+		/* Clock not in sync and XRC is enabled. Try again later. */
+		dasd_sfree_request(cqr, device);
+		return ERR_PTR(-EAGAIN);
+	}
 	/* Build locate_record+read/write/ccws. */
 	/* Build locate_record+read/write/ccws. */
 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
 	cqr->device = device;
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 	cqr->device = device;
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
 	cqr->device = device;
 	cqr->device = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->retries = 0;
+	cqr->retries = 2;	/* set retry counter to enable basic ERP */
 	cqr->expires = 2 * HZ;
 	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
  * Dump the range of CCWs into 'page' buffer
  * Dump the range of CCWs into 'page' buffer
  * and return number of printed chars.
  * and return number of printed chars.
  */
  */
-static inline int
+static int
 dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 {
 {
 	int len, count;
 	int len, count;

+ 17 - 7
drivers/s390/block/dasd_eer.c

@@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 };
 };
 
 
-static struct miscdevice dasd_eer_dev = {
-	.minor	    = MISC_DYNAMIC_MINOR,
-	.name	    = "dasd_eer",
-	.fops	    = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
 
 
 int __init dasd_eer_init(void)
 int __init dasd_eer_init(void)
 {
 {
 	int rc;
 	int rc;
 
 
-	rc = misc_register(&dasd_eer_dev);
+	dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+	if (!dasd_eer_dev)
+		return -ENOMEM;
+
+	dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+	dasd_eer_dev->name  = "dasd_eer";
+	dasd_eer_dev->fops  = &dasd_eer_fops;
+
+	rc = misc_register(dasd_eer_dev);
 	if (rc) {
 	if (rc) {
+		kfree(dasd_eer_dev);
+		dasd_eer_dev = NULL;
 		MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
 		MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
 		       "register misc device");
 		       "register misc device");
 		return rc;
 		return rc;
@@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
 
 
 void dasd_eer_exit(void)
 void dasd_eer_exit(void)
 {
 {
-	WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+	if (dasd_eer_dev) {
+		WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+		kfree(dasd_eer_dev);
+		dasd_eer_dev = NULL;
+	}
 }
 }

+ 0 - 80
drivers/s390/block/dasd_erp.c

@@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 
 
 }				/* end default_erp_postaction */
 }				/* end default_erp_postaction */
 
 
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
-	int *pint;
-
-	pint = (int *) data;
-	while (len > 0) {
-		DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
-			    pint, pint[0], pint[1], pint[2], pint[3]);
-		pint += 4;
-		len -= 16;
-	}
-}
-
 void
 void
 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 {
 {
@@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 		device->discipline->dump_sense(device, cqr, irb);
 		device->discipline->dump_sense(device, cqr, irb);
 }
 }
 
 
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
-	struct dasd_device *device;
-	struct dasd_ccw_req *lcqr;
-	struct ccw1 *ccw;
-	int cplength;
-
-	device = cqr->device;
-	/* log the channel program */
-	for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
-		DEV_MESSAGE(KERN_ERR, device,
-			    "(%s) ERP chain report for req: %p",
-			    caller == 0 ? "EXAMINE" : "ACTION", lcqr);
-		hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
-		cplength = 1;
-		ccw = lcqr->cpaddr;
-		while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
-			cplength++;
-
-		if (cplength > 40) {	/* log only parts of the CP */
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Start of channel program:");
-			hex_dump_memory(device, lcqr->cpaddr,
-					40*sizeof(struct ccw1));
-
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "End of channel program:");
-			hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
-					10*sizeof(struct ccw1));
-		} else {	/* log the whole CP */
-			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Channel program (complete):");
-			hex_dump_memory(device, lcqr->cpaddr,
-					cplength*sizeof(struct ccw1));
-		}
-
-		if (lcqr != cqr)
-			continue;
-
-		/*
-		 * Log bytes arround failed CCW but only if we did
-		 * not log the whole CP of the CCW is outside the
-		 * logged CP.
-		 */
-		if (cplength > 40 ||
-		    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
-		     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
-			DEV_MESSAGE(KERN_ERR, device,
-				    "Failed CCW (%p) (area):",
-				    (void *) (long) cpa);
-			hex_dump_memory(device, cqr->cpaddr - 10,
-					20*sizeof(struct ccw1));
-		}
-	}
-
-}				/* end log_erp_chain */
-
 EXPORT_SYMBOL(dasd_default_erp_action);
 EXPORT_SYMBOL(dasd_default_erp_action);
 EXPORT_SYMBOL(dasd_default_erp_postaction);
 EXPORT_SYMBOL(dasd_default_erp_postaction);
 EXPORT_SYMBOL(dasd_alloc_erp_request);
 EXPORT_SYMBOL(dasd_alloc_erp_request);
 EXPORT_SYMBOL(dasd_free_erp_request);
 EXPORT_SYMBOL(dasd_free_erp_request);
 EXPORT_SYMBOL(dasd_log_sense);
 EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);

+ 2 - 2
drivers/s390/block/dasd_fba.c

@@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
 	.notify      = dasd_generic_notify,
 	.notify      = dasd_generic_notify,
 };
 };
 
 
-static inline void
+static void
 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
 	      int blksize, int beg, int nr)
 	      int blksize, int beg, int nr)
 {
 {
@@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
 	data->ext_end = nr - 1;
 	data->ext_end = nr - 1;
 }
 }
 
 
-static inline void
+static void
 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
 	      int block_nr, int block_ct)
 	      int block_nr, int block_ct)
 {
 {

+ 1 - 1
drivers/s390/block/dasd_genhd.c

@@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
 	 */
 	 */
 	memset(&bpart, 0, sizeof(struct blkpg_partition));
 	memset(&bpart, 0, sizeof(struct blkpg_partition));
 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
-	barg.data = (void __user *) &bpart;
+	barg.data = (void __force __user *) &bpart;
 	barg.op = BLKPG_DEL_PARTITION;
 	barg.op = BLKPG_DEL_PARTITION;
 	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
 	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);

+ 0 - 1
drivers/s390/block/dasd_int.h

@@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
 					    struct dasd_device *);
 					    struct dasd_device *);
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
 
 
 /* externals in dasd_3370_erp.c */
 /* externals in dasd_3370_erp.c */
 dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
 dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);

+ 4 - 4
drivers/s390/block/dasd_proc.c

@@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
 static struct proc_dir_entry *dasd_devices_entry = NULL;
 static struct proc_dir_entry *dasd_devices_entry = NULL;
 static struct proc_dir_entry *dasd_statistics_entry = NULL;
 static struct proc_dir_entry *dasd_statistics_entry = NULL;
 
 
-static inline char *
+static char *
 dasd_get_user_string(const char __user *user_buf, size_t user_len)
 dasd_get_user_string(const char __user *user_buf, size_t user_len)
 {
 {
 	char *buffer;
 	char *buffer;
@@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
 	.release	= seq_release,
 	.release	= seq_release,
 };
 };
 
 
-static inline int
+static int
 dasd_calc_metrics(char *page, char **start, off_t off,
 dasd_calc_metrics(char *page, char **start, off_t off,
 		  int count, int *eof, int len)
 		  int count, int *eof, int len)
 {
 {
@@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
 	return len;
 	return len;
 }
 }
 
 
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
 {
 {
 	int i;
 	int i;
 
 

+ 3 - 3
drivers/s390/block/dcssblk.c

@@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
  * device needs to be enqueued before the semaphore is
  * device needs to be enqueued before the semaphore is
  * freed.
  * freed.
  */
  */
-static inline int
+static int
 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
 {
 {
 	int minor, found;
 	int minor, found;
@@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
 					   SEGMENT_SHARED);
 					   SEGMENT_SHARED);
 		if (rc < 0) {
 		if (rc < 0) {
 			BUG_ON(rc == -EINVAL);
 			BUG_ON(rc == -EINVAL);
-			if (rc == -EIO || rc == -ENOENT)
+			if (rc != -EAGAIN)
 				goto removeseg;
 				goto removeseg;
 		} else {
 		} else {
 			dev_info->is_shared = 1;
 			dev_info->is_shared = 1;
@@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
 					   SEGMENT_EXCLUSIVE);
 					   SEGMENT_EXCLUSIVE);
 		if (rc < 0) {
 		if (rc < 0) {
 			BUG_ON(rc == -EINVAL);
 			BUG_ON(rc == -EINVAL);
-			if (rc == -EIO || rc == -ENOENT)
+			if (rc != -EAGAIN)
 				goto removeseg;
 				goto removeseg;
 		} else {
 		} else {
 			dev_info->is_shared = 0;
 			dev_info->is_shared = 0;

+ 2 - 2
drivers/s390/char/Makefile

@@ -2,7 +2,8 @@
 # S/390 character devices
 # S/390 character devices
 #
 #
 
 
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+	 sclp_info.o
 
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
 
 
 obj-$(CONFIG_TN3215) += con3215.o
 obj-$(CONFIG_TN3215) += con3215.o
 
 
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
 obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
 obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o

+ 1 - 1
drivers/s390/char/con3215.c

@@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
  * 3215 tty registration code called from tty_init().
  * 3215 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
  */
-int __init
+static int __init
 tty3215_init(void)
 tty3215_init(void)
 {
 {
 	struct tty_driver *driver;
 	struct tty_driver *driver;

+ 1 - 2
drivers/s390/char/con3270.c

@@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
 /*
 /*
  * Setup timeout for a device. On timeout trigger an update.
  * Setup timeout for a device. On timeout trigger an update.
  */
  */
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
 {
 {
 	if (expires == 0) {
 	if (expires == 0) {
 		if (timer_pending(&cp->timer))
 		if (timer_pending(&cp->timer))

+ 2 - 0
drivers/s390/char/defkeymap.c

@@ -5,6 +5,8 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/keyboard.h>
 #include <linux/keyboard.h>
 #include <linux/kd.h>
 #include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
 
 
 u_short plain_map[NR_KEYS] = {
 u_short plain_map[NR_KEYS] = {
 	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,
 	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,	0xf000,

+ 2 - 2
drivers/s390/char/fs3270.c

@@ -23,7 +23,7 @@
 #include "raw3270.h"
 #include "raw3270.h"
 #include "ctrlchar.h"
 #include "ctrlchar.h"
 
 
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
 
 
 struct fs3270 {
 struct fs3270 {
 	struct raw3270_view view;
 	struct raw3270_view view;
@@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
 }
 }
 
 
 /* View to a 3270 device. Can be console, tty or fullscreen. */
 /* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
 	.activate = fs3270_activate,
 	.activate = fs3270_activate,
 	.deactivate = fs3270_deactivate,
 	.deactivate = fs3270_deactivate,
 	.intv = (void *) fs3270_irq,
 	.intv = (void *) fs3270_irq,

+ 2 - 0
drivers/s390/char/keyboard.c

@@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
 	}
 	}
 }
 }
 
 
+#if 0
 /*
 /*
  * Generate ebcdic -> ascii translation table from kbd_data.
  * Generate ebcdic -> ascii translation table from kbd_data.
  */
  */
@@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
 		}
 		}
 	}
 	}
 }
 }
+#endif
 
 
 /*
 /*
  * We have a combining character DIACR here, followed by the character CH.
  * We have a combining character DIACR here, followed by the character CH.

+ 2 - 2
drivers/s390/char/monwriter.c

@@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
-						struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+					 struct monwrite_hdr *monhdr)
 {
 {
 	struct mon_buf *entry, *next;
 	struct mon_buf *entry, *next;
 
 

+ 2 - 2
drivers/s390/char/raw3270.c

@@ -29,7 +29,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 
 
-struct class *class3270;
+static struct class *class3270;
 
 
 /* The main 3270 data structure. */
 /* The main 3270 data structure. */
 struct raw3270 {
 struct raw3270 {
@@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
 /*
 /*
  * Encode array for 12 bit 3270 addresses.
  * Encode array for 12 bit 3270 addresses.
  */
  */
-unsigned char raw3270_ebcgraf[64] =	{
+static unsigned char raw3270_ebcgraf[64] =	{
 	0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
 	0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
 	0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
 	0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
 	0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
 	0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,

+ 62 - 31
drivers/s390/char/sclp.c

@@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
 /* Internal state: is a request active at the sclp? */
 /* Internal state: is a request active at the sclp? */
 static volatile enum sclp_running_state_t {
 static volatile enum sclp_running_state_t {
 	sclp_running_state_idle,
 	sclp_running_state_idle,
-	sclp_running_state_running
+	sclp_running_state_running,
+	sclp_running_state_reset_pending
 } sclp_running_state = sclp_running_state_idle;
 } sclp_running_state = sclp_running_state_idle;
 
 
 /* Internal state: is a read request pending? */
 /* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
 
 
 /* Timeout intervals in seconds.*/
 /* Timeout intervals in seconds.*/
 #define SCLP_BUSY_INTERVAL	10
 #define SCLP_BUSY_INTERVAL	10
-#define SCLP_RETRY_INTERVAL	15
+#define SCLP_RETRY_INTERVAL	30
 
 
 static void sclp_process_queue(void);
 static void sclp_process_queue(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 static int sclp_init(void);
 
 
 /* Perform service call. Return 0 on success, non-zero otherwise. */
 /* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
 {
 {
 	int cc;
 	int cc;
 
 
@@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
 	return 0;
 	return 0;
 }
 }
 
 
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
+static inline void __sclp_make_read_req(void);
+
 static void
 static void
-sclp_request_timeout(unsigned long data)
+__sclp_queue_read_req(void)
 {
 {
-	unsigned long flags;
-
-	if (data) {
-		spin_lock_irqsave(&sclp_lock, flags);
-		sclp_running_state = sclp_running_state_idle;
-		spin_unlock_irqrestore(&sclp_lock, flags);
+	if (sclp_reading_state == sclp_reading_state_idle) {
+		sclp_reading_state = sclp_reading_state_reading;
+		__sclp_make_read_req();
+		/* Add request to head of queue */
+		list_add(&sclp_read_req.list, &sclp_req_queue);
 	}
 	}
-	sclp_process_queue();
 }
 }
 
 
 /* Set up request retry timer. Called while sclp_lock is locked. */
 /* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
 	add_timer(&sclp_request_timer);
 	add_timer(&sclp_request_timer);
 }
 }
 
 
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sclp_lock, flags);
+	if (data) {
+		if (sclp_running_state == sclp_running_state_running) {
+			/* Break running state and queue NOP read event request
+			 * to get a defined interface state. */
+			__sclp_queue_read_req();
+			sclp_running_state = sclp_running_state_idle;
+		}
+	} else {
+		__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+					 sclp_request_timeout, 0);
+	}
+	spin_unlock_irqrestore(&sclp_lock, flags);
+	sclp_process_queue();
+}
+
 /* Try to start a request. Return zero if the request was successfully
 /* Try to start a request. Return zero if the request was successfully
  * started or if it will be started at a later time. Return non-zero otherwise.
  * started or if it will be started at a later time. Return non-zero otherwise.
  * Called while sclp_lock is locked. */
  * Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
 	if (sclp_running_state != sclp_running_state_idle)
 	if (sclp_running_state != sclp_running_state_idle)
 		return 0;
 		return 0;
 	del_timer(&sclp_request_timer);
 	del_timer(&sclp_request_timer);
-	rc = service_call(req->command, req->sccb);
+	rc = sclp_service_call(req->command, req->sccb);
 	req->start_count++;
 	req->start_count++;
 
 
 	if (rc == 0) {
 	if (rc == 0) {
@@ -191,7 +213,15 @@ sclp_process_queue(void)
 		rc = __sclp_start_request(req);
 		rc = __sclp_start_request(req);
 		if (rc == 0)
 		if (rc == 0)
 			break;
 			break;
-		/* Request failed. */
+		/* Request failed */
+		if (req->start_count > 1) {
+			/* Cannot abort already submitted request - could still
+			 * be active at the SCLP */
+			__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+						 sclp_request_timeout, 0);
+			break;
+		}
+		/* Post-processing for aborted request */
 		list_del(&req->list);
 		list_del(&req->list);
 		if (req->callback) {
 		if (req->callback) {
 			spin_unlock_irqrestore(&sclp_lock, flags);
 			spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
 	list_add_tail(&req->list, &sclp_req_queue);
 	list_add_tail(&req->list, &sclp_req_queue);
 	rc = 0;
 	rc = 0;
 	/* Start if request is first in list */
 	/* Start if request is first in list */
-	if (req->list.prev == &sclp_req_queue) {
+	if (sclp_running_state == sclp_running_state_idle &&
+	    req->list.prev == &sclp_req_queue) {
 		rc = __sclp_start_request(req);
 		rc = __sclp_start_request(req);
 		if (rc)
 		if (rc)
 			list_del(&req->list);
 			list_del(&req->list);
@@ -294,7 +325,7 @@ __sclp_make_read_req(void)
 	sccb = (struct sccb_header *) sclp_read_sccb;
 	sccb = (struct sccb_header *) sclp_read_sccb;
 	clear_page(sccb);
 	clear_page(sccb);
 	memset(&sclp_read_req, 0, sizeof(struct sclp_req));
 	memset(&sclp_read_req, 0, sizeof(struct sclp_req));
-	sclp_read_req.command = SCLP_CMDW_READDATA;
+	sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
 	sclp_read_req.status = SCLP_REQ_QUEUED;
 	sclp_read_req.status = SCLP_REQ_QUEUED;
 	sclp_read_req.start_count = 0;
 	sclp_read_req.start_count = 0;
 	sclp_read_req.callback = sclp_read_cb;
 	sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
 	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
 	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
 	evbuf_pending = S390_lowcore.ext_params & 0x3;
 	evbuf_pending = S390_lowcore.ext_params & 0x3;
 	if (finished_sccb) {
 	if (finished_sccb) {
+		del_timer(&sclp_request_timer);
+		sclp_running_state = sclp_running_state_reset_pending;
 		req = __sclp_find_req(finished_sccb);
 		req = __sclp_find_req(finished_sccb);
 		if (req) {
 		if (req) {
 			/* Request post-processing */
 			/* Request post-processing */
@@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
 		sclp_running_state = sclp_running_state_idle;
 		sclp_running_state = sclp_running_state_idle;
 	}
 	}
 	if (evbuf_pending && sclp_receive_mask != 0 &&
 	if (evbuf_pending && sclp_receive_mask != 0 &&
-	    sclp_reading_state == sclp_reading_state_idle &&
-	    sclp_activation_state == sclp_activation_state_active ) {
-		sclp_reading_state = sclp_reading_state_reading;
-		__sclp_make_read_req();
-		/* Add request to head of queue */
-		list_add(&sclp_read_req.list, &sclp_req_queue);
-	}
+	    sclp_activation_state == sclp_activation_state_active)
+		__sclp_queue_read_req();
 	spin_unlock(&sclp_lock);
 	spin_unlock(&sclp_lock);
 	sclp_process_queue();
 	sclp_process_queue();
 }
 }
@@ -374,6 +402,7 @@ sclp_sync_wait(void)
 	unsigned long flags;
 	unsigned long flags;
 	unsigned long cr0, cr0_sync;
 	unsigned long cr0, cr0_sync;
 	u64 timeout;
 	u64 timeout;
+	int irq_context;
 
 
 	/* We'll be disabling timer interrupts, so we need a custom timeout
 	/* We'll be disabling timer interrupts, so we need a custom timeout
 	 * mechanism */
 	 * mechanism */
@@ -386,7 +415,9 @@ sclp_sync_wait(void)
 	}
 	}
 	local_irq_save(flags);
 	local_irq_save(flags);
 	/* Prevent bottom half from executing once we force interrupts open */
 	/* Prevent bottom half from executing once we force interrupts open */
-	local_bh_disable();
+	irq_context = in_interrupt();
+	if (!irq_context)
+		local_bh_disable();
 	/* Enable service-signal interruption, disable timer interrupts */
 	/* Enable service-signal interruption, disable timer interrupts */
 	trace_hardirqs_on();
 	trace_hardirqs_on();
 	__ctl_store(cr0, 0, 0);
 	__ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@ sclp_sync_wait(void)
 		    get_clock() > timeout &&
 		    get_clock() > timeout &&
 		    del_timer(&sclp_request_timer))
 		    del_timer(&sclp_request_timer))
 			sclp_request_timer.function(sclp_request_timer.data);
 			sclp_request_timer.function(sclp_request_timer.data);
-		barrier();
 		cpu_relax();
 		cpu_relax();
 	}
 	}
 	local_irq_disable();
 	local_irq_disable();
 	__ctl_load(cr0, 0, 0);
 	__ctl_load(cr0, 0, 0);
-	_local_bh_enable();
+	if (!irq_context)
+		_local_bh_enable();
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
 
 
 EXPORT_SYMBOL(sclp_sync_wait);
 EXPORT_SYMBOL(sclp_sync_wait);
 
 
 /* Dispatch changes in send and receive mask to registered listeners. */
 /* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
 sclp_dispatch_state_change(void)
 sclp_dispatch_state_change(void)
 {
 {
 	struct list_head *l;
 	struct list_head *l;
@@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
 	sccb = (struct init_sccb *) sclp_init_sccb;
 	sccb = (struct init_sccb *) sclp_init_sccb;
 	clear_page(sccb);
 	clear_page(sccb);
 	memset(&sclp_init_req, 0, sizeof(struct sclp_req));
 	memset(&sclp_init_req, 0, sizeof(struct sclp_req));
-	sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+	sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
 	sclp_init_req.status = SCLP_REQ_FILLED;
 	sclp_init_req.status = SCLP_REQ_FILLED;
 	sclp_init_req.start_count = 0;
 	sclp_init_req.start_count = 0;
 	sclp_init_req.callback = NULL;
 	sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@ sclp_check_interface(void)
 	for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
 	for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
 		__sclp_make_init_req(0, 0);
 		__sclp_make_init_req(0, 0);
 		sccb = (struct init_sccb *) sclp_init_req.sccb;
 		sccb = (struct init_sccb *) sclp_init_req.sccb;
-		rc = service_call(sclp_init_req.command, sccb);
+		rc = sclp_service_call(sclp_init_req.command, sccb);
 		if (rc == -EIO)
 		if (rc == -EIO)
 			break;
 			break;
 		sclp_init_req.status = SCLP_REQ_RUNNING;
 		sclp_init_req.status = SCLP_REQ_RUNNING;

+ 7 - 11
drivers/s390/char/sclp.h

@@ -12,7 +12,7 @@
 
 
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/list.h>
-
+#include <asm/sclp.h>
 #include <asm/ebcdic.h>
 #include <asm/ebcdic.h>
 
 
 /* maximum number of pages concerning our own memory management */
 /* maximum number of pages concerning our own memory management */
@@ -49,9 +49,11 @@
 
 
 typedef unsigned int sclp_cmdw_t;
 typedef unsigned int sclp_cmdw_t;
 
 
-#define SCLP_CMDW_READDATA	0x00770005
-#define SCLP_CMDW_WRITEDATA	0x00760005
-#define SCLP_CMDW_WRITEMASK	0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA	0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
+#define SCLP_CMDW_READ_SCP_INFO		0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
 
 
 #define GDS_ID_MDSMU		0x1310
 #define GDS_ID_MDSMU		0x1310
 #define GDS_ID_MDSRouteInfo	0x1311
 #define GDS_ID_MDSRouteInfo	0x1311
@@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
 
 
 typedef u32 sccb_mask_t;	/* ATTENTION: assumes 32bit mask !!! */
 typedef u32 sccb_mask_t;	/* ATTENTION: assumes 32bit mask !!! */
 
 
-struct sccb_header {
-	u16	length;
-	u8	function_code;
-	u8	control_mask[3];
-	u16	response_code;
-} __attribute__((packed));
-
 struct gds_subvector {
 struct gds_subvector {
 	u8	length;
 	u8	length;
 	u8	key;
 	u8	key;
@@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
 int sclp_remove_processed(struct sccb_header *sccb);
 int sclp_remove_processed(struct sccb_header *sccb);
 int sclp_deactivate(void);
 int sclp_deactivate(void);
 int sclp_reactivate(void);
 int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
 
 
 /* useful inlines */
 /* useful inlines */
 
 

+ 1 - 1
drivers/s390/char/sclp_con.c

@@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
 	} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
 	} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
 }
 }
 
 
-static inline void
+static void
 sclp_conbuf_emit(void)
 sclp_conbuf_emit(void)
 {
 {
 	struct sclp_buffer* buffer;
 	struct sclp_buffer* buffer;

+ 1 - 1
drivers/s390/char/sclp_cpi.c

@@ -169,7 +169,7 @@ cpi_prepare_req(void)
 	}
 	}
 
 
 	/* prepare request data structure presented to SCLP driver */
 	/* prepare request data structure presented to SCLP driver */
-	req->command = SCLP_CMDW_WRITEDATA;
+	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
 	req->sccb = sccb;
 	req->sccb = sccb;
 	req->status = SCLP_REQ_FILLED;
 	req->status = SCLP_REQ_FILLED;
 	req->callback = cpi_callback;
 	req->callback = cpi_callback;

+ 57 - 0
drivers/s390/char/sclp_info.c

@@ -0,0 +1,57 @@
+/*
+ *  drivers/s390/char/sclp_info.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+	sclp_cmdw_t command;
+	struct sccb_header *sccb;
+	int ret;
+
+	__ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+	sccb = &s390_readinfo_sccb.header;
+	command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+	while (1) {
+		u16 response;
+
+		memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+		sccb->length = sizeof(s390_readinfo_sccb);
+		sccb->control_mask[2] = 0x80;
+
+		ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+		if (ret == -EIO)
+			goto out;
+		if (ret == -EBUSY)
+			continue;
+
+		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+		local_irq_disable();
+		barrier();
+
+		response = sccb->response_code;
+
+		if (response == 0x10)
+			break;
+
+		if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+			break;
+
+		command = SCLP_CMDW_READ_SCP_INFO;
+	}
+out:
+	__ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}

+ 1 - 1
drivers/s390/char/sclp_rw.c

@@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
 		sccb->msg_buf.header.type = EvTyp_PMsgCmd;
 		sccb->msg_buf.header.type = EvTyp_PMsgCmd;
 	else
 	else
 		return -ENOSYS;
 		return -ENOSYS;
-	buffer->request.command = SCLP_CMDW_WRITEDATA;
+	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
 	buffer->request.status = SCLP_REQ_FILLED;
 	buffer->request.status = SCLP_REQ_FILLED;
 	buffer->request.callback = sclp_writedata_callback;
 	buffer->request.callback = sclp_writedata_callback;
 	buffer->request.callback_data = buffer;
 	buffer->request.callback_data = buffer;

+ 1 - 1
drivers/s390/char/sclp_tty.c

@@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = {
 	.ioctl = sclp_tty_ioctl,
 	.ioctl = sclp_tty_ioctl,
 };
 };
 
 
-int __init
+static int __init
 sclp_tty_init(void)
 sclp_tty_init(void)
 {
 {
 	struct tty_driver *driver;
 	struct tty_driver *driver;

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно