diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:02:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:02:14 -0400 |
commit | 9fd815b55f31be48dbb3dd23922587d247a4e497 (patch) | |
tree | 63814130acf3e472cc660ae71208c146f16dc5d6 | |
parent | 31bbb9b58d1e8ebcf2b28c95c2250a9f8e31e397 (diff) | |
parent | ed87b27e00d2ca240f62f3903583a2f1541fb9ef (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (22 commits)
[S390] Update default configuration.
[S390] hibernate: Do real CPU swap at resume time
[S390] dasd: tolerate devices that have no feature codes
[S390] zcrypt: Do not add/remove devices in s/r callbacks
[S390] hibernate: make sure pfn_is_nosave handles lowcore pages
[S390] smp: introduce LC_ORDER and simplify lowcore handling
[S390] ptrace: use common code for simple peek/poke operations
[S390] fix disabled_wait inline assembly clobber list
[S390] Change kernel_page_present coding style.
[S390] hibernation: reset system after resume
[S390] hibernation: fix guest page hinting related crash
[S390] Get rid of init_module/delete_module compat functions.
[S390] Convert sys_execve to function with parameters.
[S390] Convert sys_clone to function with parameters.
[S390] qdio: change state of all primed input buffers
[S390] qdio: reduce per device debug messages
[S390] cio: introduce consistent subchannel scanning
[S390] cio: idset use actual number of ssids
[S390] cio: dont kfree vmalloced memory
[S390] cio: introduce css_settle
...
26 files changed, 478 insertions, 417 deletions
diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 4e91a2573cc4..ab4464486b7a 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.30 | 3 | # Linux kernel version: 2.6.31 |
4 | # Mon Jun 22 11:08:16 2009 | 4 | # Tue Sep 22 17:43:13 2009 |
5 | # | 5 | # |
6 | CONFIG_SCHED_MC=y | 6 | CONFIG_SCHED_MC=y |
7 | CONFIG_MMU=y | 7 | CONFIG_MMU=y |
@@ -24,6 +24,7 @@ CONFIG_PGSTE=y | |||
24 | CONFIG_VIRT_CPU_ACCOUNTING=y | 24 | CONFIG_VIRT_CPU_ACCOUNTING=y |
25 | CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y | 25 | CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y |
26 | CONFIG_S390=y | 26 | CONFIG_S390=y |
27 | CONFIG_SCHED_OMIT_FRAME_POINTER=y | ||
27 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 28 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
28 | CONFIG_CONSTRUCTORS=y | 29 | CONFIG_CONSTRUCTORS=y |
29 | 30 | ||
@@ -48,11 +49,12 @@ CONFIG_AUDIT=y | |||
48 | # | 49 | # |
49 | # RCU Subsystem | 50 | # RCU Subsystem |
50 | # | 51 | # |
51 | CONFIG_CLASSIC_RCU=y | 52 | CONFIG_TREE_RCU=y |
52 | # CONFIG_TREE_RCU is not set | 53 | # CONFIG_TREE_PREEMPT_RCU is not set |
53 | # CONFIG_PREEMPT_RCU is not set | 54 | # CONFIG_RCU_TRACE is not set |
55 | CONFIG_RCU_FANOUT=64 | ||
56 | # CONFIG_RCU_FANOUT_EXACT is not set | ||
54 | # CONFIG_TREE_RCU_TRACE is not set | 57 | # CONFIG_TREE_RCU_TRACE is not set |
55 | # CONFIG_PREEMPT_RCU_TRACE is not set | ||
56 | CONFIG_IKCONFIG=y | 58 | CONFIG_IKCONFIG=y |
57 | CONFIG_IKCONFIG_PROC=y | 59 | CONFIG_IKCONFIG_PROC=y |
58 | CONFIG_LOG_BUF_SHIFT=17 | 60 | CONFIG_LOG_BUF_SHIFT=17 |
@@ -103,11 +105,12 @@ CONFIG_TIMERFD=y | |||
103 | CONFIG_EVENTFD=y | 105 | CONFIG_EVENTFD=y |
104 | CONFIG_SHMEM=y | 106 | CONFIG_SHMEM=y |
105 | CONFIG_AIO=y | 107 | CONFIG_AIO=y |
106 | CONFIG_HAVE_PERF_COUNTERS=y | 108 | CONFIG_HAVE_PERF_EVENTS=y |
107 | 109 | ||
108 | # | 110 | # |
109 | # Performance Counters | 111 | # Kernel Performance Events And Counters |
110 | # | 112 | # |
113 | # CONFIG_PERF_EVENTS is not set | ||
111 | # CONFIG_PERF_COUNTERS is not set | 114 | # CONFIG_PERF_COUNTERS is not set |
112 | CONFIG_VM_EVENT_COUNTERS=y | 115 | CONFIG_VM_EVENT_COUNTERS=y |
113 | # CONFIG_STRIP_ASM_SYMS is not set | 116 | # CONFIG_STRIP_ASM_SYMS is not set |
@@ -116,7 +119,6 @@ CONFIG_SLAB=y | |||
116 | # CONFIG_SLUB is not set | 119 | # CONFIG_SLUB is not set |
117 | # CONFIG_SLOB is not set | 120 | # CONFIG_SLOB is not set |
118 | # CONFIG_PROFILING is not set | 121 | # CONFIG_PROFILING is not set |
119 | # CONFIG_MARKERS is not set | ||
120 | CONFIG_HAVE_OPROFILE=y | 122 | CONFIG_HAVE_OPROFILE=y |
121 | CONFIG_KPROBES=y | 123 | CONFIG_KPROBES=y |
122 | CONFIG_HAVE_SYSCALL_WRAPPERS=y | 124 | CONFIG_HAVE_SYSCALL_WRAPPERS=y |
@@ -176,6 +178,7 @@ CONFIG_NO_HZ=y | |||
176 | CONFIG_HIGH_RES_TIMERS=y | 178 | CONFIG_HIGH_RES_TIMERS=y |
177 | CONFIG_GENERIC_CLOCKEVENTS_BUILD=y | 179 | CONFIG_GENERIC_CLOCKEVENTS_BUILD=y |
178 | CONFIG_64BIT=y | 180 | CONFIG_64BIT=y |
181 | # CONFIG_KTIME_SCALAR is not set | ||
179 | CONFIG_SMP=y | 182 | CONFIG_SMP=y |
180 | CONFIG_NR_CPUS=32 | 183 | CONFIG_NR_CPUS=32 |
181 | CONFIG_HOTPLUG_CPU=y | 184 | CONFIG_HOTPLUG_CPU=y |
@@ -257,7 +260,6 @@ CONFIG_FORCE_MAX_ZONEORDER=9 | |||
257 | CONFIG_PFAULT=y | 260 | CONFIG_PFAULT=y |
258 | # CONFIG_SHARED_KERNEL is not set | 261 | # CONFIG_SHARED_KERNEL is not set |
259 | # CONFIG_CMM is not set | 262 | # CONFIG_CMM is not set |
260 | # CONFIG_PAGE_STATES is not set | ||
261 | # CONFIG_APPLDATA_BASE is not set | 263 | # CONFIG_APPLDATA_BASE is not set |
262 | CONFIG_HZ_100=y | 264 | CONFIG_HZ_100=y |
263 | # CONFIG_HZ_250 is not set | 265 | # CONFIG_HZ_250 is not set |
@@ -280,6 +282,7 @@ CONFIG_PM_SLEEP_SMP=y | |||
280 | CONFIG_PM_SLEEP=y | 282 | CONFIG_PM_SLEEP=y |
281 | CONFIG_HIBERNATION=y | 283 | CONFIG_HIBERNATION=y |
282 | CONFIG_PM_STD_PARTITION="" | 284 | CONFIG_PM_STD_PARTITION="" |
285 | # CONFIG_PM_RUNTIME is not set | ||
283 | CONFIG_NET=y | 286 | CONFIG_NET=y |
284 | 287 | ||
285 | # | 288 | # |
@@ -394,6 +397,7 @@ CONFIG_IP_SCTP=m | |||
394 | # CONFIG_SCTP_HMAC_NONE is not set | 397 | # CONFIG_SCTP_HMAC_NONE is not set |
395 | # CONFIG_SCTP_HMAC_SHA1 is not set | 398 | # CONFIG_SCTP_HMAC_SHA1 is not set |
396 | CONFIG_SCTP_HMAC_MD5=y | 399 | CONFIG_SCTP_HMAC_MD5=y |
400 | # CONFIG_RDS is not set | ||
397 | # CONFIG_TIPC is not set | 401 | # CONFIG_TIPC is not set |
398 | # CONFIG_ATM is not set | 402 | # CONFIG_ATM is not set |
399 | # CONFIG_BRIDGE is not set | 403 | # CONFIG_BRIDGE is not set |
@@ -487,6 +491,7 @@ CONFIG_CCW=y | |||
487 | # Generic Driver Options | 491 | # Generic Driver Options |
488 | # | 492 | # |
489 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 493 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
494 | # CONFIG_DEVTMPFS is not set | ||
490 | CONFIG_STANDALONE=y | 495 | CONFIG_STANDALONE=y |
491 | CONFIG_PREVENT_FIRMWARE_BUILD=y | 496 | CONFIG_PREVENT_FIRMWARE_BUILD=y |
492 | CONFIG_FW_LOADER=y | 497 | CONFIG_FW_LOADER=y |
@@ -501,6 +506,7 @@ CONFIG_BLK_DEV=y | |||
501 | CONFIG_BLK_DEV_LOOP=m | 506 | CONFIG_BLK_DEV_LOOP=m |
502 | # CONFIG_BLK_DEV_CRYPTOLOOP is not set | 507 | # CONFIG_BLK_DEV_CRYPTOLOOP is not set |
503 | CONFIG_BLK_DEV_NBD=m | 508 | CONFIG_BLK_DEV_NBD=m |
509 | # CONFIG_BLK_DEV_OSD is not set | ||
504 | CONFIG_BLK_DEV_RAM=y | 510 | CONFIG_BLK_DEV_RAM=y |
505 | CONFIG_BLK_DEV_RAM_COUNT=16 | 511 | CONFIG_BLK_DEV_RAM_COUNT=16 |
506 | CONFIG_BLK_DEV_RAM_SIZE=4096 | 512 | CONFIG_BLK_DEV_RAM_SIZE=4096 |
@@ -594,8 +600,11 @@ CONFIG_BLK_DEV_DM=y | |||
594 | CONFIG_DM_CRYPT=y | 600 | CONFIG_DM_CRYPT=y |
595 | CONFIG_DM_SNAPSHOT=y | 601 | CONFIG_DM_SNAPSHOT=y |
596 | CONFIG_DM_MIRROR=y | 602 | CONFIG_DM_MIRROR=y |
603 | # CONFIG_DM_LOG_USERSPACE is not set | ||
597 | CONFIG_DM_ZERO=y | 604 | CONFIG_DM_ZERO=y |
598 | CONFIG_DM_MULTIPATH=m | 605 | CONFIG_DM_MULTIPATH=m |
606 | # CONFIG_DM_MULTIPATH_QL is not set | ||
607 | # CONFIG_DM_MULTIPATH_ST is not set | ||
599 | # CONFIG_DM_DELAY is not set | 608 | # CONFIG_DM_DELAY is not set |
600 | # CONFIG_DM_UEVENT is not set | 609 | # CONFIG_DM_UEVENT is not set |
601 | CONFIG_NETDEVICES=y | 610 | CONFIG_NETDEVICES=y |
@@ -615,7 +624,6 @@ CONFIG_NET_ETHERNET=y | |||
615 | # CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set | 624 | # CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set |
616 | # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set | 625 | # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set |
617 | # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set | 626 | # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set |
618 | # CONFIG_KS8842 is not set | ||
619 | CONFIG_NETDEV_1000=y | 627 | CONFIG_NETDEV_1000=y |
620 | CONFIG_NETDEV_10000=y | 628 | CONFIG_NETDEV_10000=y |
621 | # CONFIG_TR is not set | 629 | # CONFIG_TR is not set |
@@ -678,6 +686,7 @@ CONFIG_SCLP_CONSOLE=y | |||
678 | CONFIG_SCLP_VT220_TTY=y | 686 | CONFIG_SCLP_VT220_TTY=y |
679 | CONFIG_SCLP_VT220_CONSOLE=y | 687 | CONFIG_SCLP_VT220_CONSOLE=y |
680 | CONFIG_SCLP_CPI=m | 688 | CONFIG_SCLP_CPI=m |
689 | CONFIG_SCLP_ASYNC=m | ||
681 | CONFIG_S390_TAPE=m | 690 | CONFIG_S390_TAPE=m |
682 | 691 | ||
683 | # | 692 | # |
@@ -737,6 +746,7 @@ CONFIG_FS_POSIX_ACL=y | |||
737 | # CONFIG_GFS2_FS is not set | 746 | # CONFIG_GFS2_FS is not set |
738 | # CONFIG_OCFS2_FS is not set | 747 | # CONFIG_OCFS2_FS is not set |
739 | # CONFIG_BTRFS_FS is not set | 748 | # CONFIG_BTRFS_FS is not set |
749 | # CONFIG_NILFS2_FS is not set | ||
740 | CONFIG_FILE_LOCKING=y | 750 | CONFIG_FILE_LOCKING=y |
741 | CONFIG_FSNOTIFY=y | 751 | CONFIG_FSNOTIFY=y |
742 | CONFIG_DNOTIFY=y | 752 | CONFIG_DNOTIFY=y |
@@ -798,7 +808,6 @@ CONFIG_MISC_FILESYSTEMS=y | |||
798 | # CONFIG_SYSV_FS is not set | 808 | # CONFIG_SYSV_FS is not set |
799 | # CONFIG_UFS_FS is not set | 809 | # CONFIG_UFS_FS is not set |
800 | # CONFIG_EXOFS_FS is not set | 810 | # CONFIG_EXOFS_FS is not set |
801 | # CONFIG_NILFS2_FS is not set | ||
802 | CONFIG_NETWORK_FILESYSTEMS=y | 811 | CONFIG_NETWORK_FILESYSTEMS=y |
803 | CONFIG_NFS_FS=y | 812 | CONFIG_NFS_FS=y |
804 | CONFIG_NFS_V3=y | 813 | CONFIG_NFS_V3=y |
@@ -885,11 +894,13 @@ CONFIG_DEBUG_MEMORY_INIT=y | |||
885 | # CONFIG_DEBUG_LIST is not set | 894 | # CONFIG_DEBUG_LIST is not set |
886 | # CONFIG_DEBUG_SG is not set | 895 | # CONFIG_DEBUG_SG is not set |
887 | # CONFIG_DEBUG_NOTIFIERS is not set | 896 | # CONFIG_DEBUG_NOTIFIERS is not set |
897 | # CONFIG_DEBUG_CREDENTIALS is not set | ||
888 | # CONFIG_RCU_TORTURE_TEST is not set | 898 | # CONFIG_RCU_TORTURE_TEST is not set |
889 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set | 899 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set |
890 | # CONFIG_KPROBES_SANITY_TEST is not set | 900 | # CONFIG_KPROBES_SANITY_TEST is not set |
891 | # CONFIG_BACKTRACE_SELF_TEST is not set | 901 | # CONFIG_BACKTRACE_SELF_TEST is not set |
892 | # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set | 902 | # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set |
903 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | ||
893 | # CONFIG_LKDTM is not set | 904 | # CONFIG_LKDTM is not set |
894 | # CONFIG_FAULT_INJECTION is not set | 905 | # CONFIG_FAULT_INJECTION is not set |
895 | # CONFIG_LATENCYTOP is not set | 906 | # CONFIG_LATENCYTOP is not set |
@@ -979,11 +990,13 @@ CONFIG_CRYPTO_PCBC=m | |||
979 | # | 990 | # |
980 | CONFIG_CRYPTO_HMAC=m | 991 | CONFIG_CRYPTO_HMAC=m |
981 | # CONFIG_CRYPTO_XCBC is not set | 992 | # CONFIG_CRYPTO_XCBC is not set |
993 | CONFIG_CRYPTO_VMAC=m | ||
982 | 994 | ||
983 | # | 995 | # |
984 | # Digest | 996 | # Digest |
985 | # | 997 | # |
986 | CONFIG_CRYPTO_CRC32C=m | 998 | CONFIG_CRYPTO_CRC32C=m |
999 | CONFIG_CRYPTO_GHASH=m | ||
987 | # CONFIG_CRYPTO_MD4 is not set | 1000 | # CONFIG_CRYPTO_MD4 is not set |
988 | CONFIG_CRYPTO_MD5=m | 1001 | CONFIG_CRYPTO_MD5=m |
989 | # CONFIG_CRYPTO_MICHAEL_MIC is not set | 1002 | # CONFIG_CRYPTO_MICHAEL_MIC is not set |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 6bc9426a6fbf..f2ef4b619ce1 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -86,6 +86,7 @@ | |||
86 | #define __LC_PGM_OLD_PSW 0x0150 | 86 | #define __LC_PGM_OLD_PSW 0x0150 |
87 | #define __LC_MCK_OLD_PSW 0x0160 | 87 | #define __LC_MCK_OLD_PSW 0x0160 |
88 | #define __LC_IO_OLD_PSW 0x0170 | 88 | #define __LC_IO_OLD_PSW 0x0170 |
89 | #define __LC_RESTART_PSW 0x01a0 | ||
89 | #define __LC_EXT_NEW_PSW 0x01b0 | 90 | #define __LC_EXT_NEW_PSW 0x01b0 |
90 | #define __LC_SVC_NEW_PSW 0x01c0 | 91 | #define __LC_SVC_NEW_PSW 0x01c0 |
91 | #define __LC_PGM_NEW_PSW 0x01d0 | 92 | #define __LC_PGM_NEW_PSW 0x01d0 |
@@ -189,6 +190,14 @@ union save_area { | |||
189 | #define SAVE_AREA_BASE SAVE_AREA_BASE_S390X | 190 | #define SAVE_AREA_BASE SAVE_AREA_BASE_S390X |
190 | #endif | 191 | #endif |
191 | 192 | ||
193 | #ifndef __s390x__ | ||
194 | #define LC_ORDER 0 | ||
195 | #else | ||
196 | #define LC_ORDER 1 | ||
197 | #endif | ||
198 | |||
199 | #define LC_PAGES (1UL << LC_ORDER) | ||
200 | |||
192 | struct _lowcore | 201 | struct _lowcore |
193 | { | 202 | { |
194 | #ifndef __s390x__ | 203 | #ifndef __s390x__ |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index cf8eed3fa779..b42715458312 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -295,7 +295,7 @@ static inline void ATTRIB_NORET disabled_wait(unsigned long code) | |||
295 | " oi 0x384(1),0x10\n"/* fake protection bit */ | 295 | " oi 0x384(1),0x10\n"/* fake protection bit */ |
296 | " lpswe 0(%1)" | 296 | " lpswe 0(%1)" |
297 | : "=m" (ctl_buf) | 297 | : "=m" (ctl_buf) |
298 | : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0"); | 298 | : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0", "1"); |
299 | #endif /* __s390x__ */ | 299 | #endif /* __s390x__ */ |
300 | while (1); | 300 | while (1); |
301 | } | 301 | } |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index fa9905ce7d0b..63e46433e81d 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/kbuild.h> | 8 | #include <linux/kbuild.h> |
9 | #include <asm/vdso.h> | 9 | #include <asm/vdso.h> |
10 | #include <asm/sigp.h> | ||
10 | 11 | ||
11 | int main(void) | 12 | int main(void) |
12 | { | 13 | { |
@@ -59,6 +60,10 @@ int main(void) | |||
59 | DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); | 60 | DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); |
60 | DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); | 61 | DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); |
61 | DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); | 62 | DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); |
62 | 63 | /* constants for SIGP */ | |
64 | DEFINE(__SIGP_STOP, sigp_stop); | ||
65 | DEFINE(__SIGP_RESTART, sigp_restart); | ||
66 | DEFINE(__SIGP_SENSE, sigp_sense); | ||
67 | DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset); | ||
63 | return 0; | 68 | return 0; |
64 | } | 69 | } |
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 9ab188d67a3d..5519cb745106 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c | |||
@@ -443,66 +443,28 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) | |||
443 | * sys32_execve() executes a new program after the asm stub has set | 443 | * sys32_execve() executes a new program after the asm stub has set |
444 | * things up for us. This should basically do what I want it to. | 444 | * things up for us. This should basically do what I want it to. |
445 | */ | 445 | */ |
446 | asmlinkage long sys32_execve(void) | 446 | asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, |
447 | compat_uptr_t __user *envp) | ||
447 | { | 448 | { |
448 | struct pt_regs *regs = task_pt_regs(current); | 449 | struct pt_regs *regs = task_pt_regs(current); |
449 | char *filename; | 450 | char *filename; |
450 | unsigned long result; | 451 | long rc; |
451 | int rc; | 452 | |
452 | 453 | filename = getname(name); | |
453 | filename = getname(compat_ptr(regs->orig_gpr2)); | 454 | rc = PTR_ERR(filename); |
454 | if (IS_ERR(filename)) { | 455 | if (IS_ERR(filename)) |
455 | result = PTR_ERR(filename); | 456 | return rc; |
456 | goto out; | 457 | rc = compat_do_execve(filename, argv, envp, regs); |
457 | } | 458 | if (rc) |
458 | rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]), | 459 | goto out; |
459 | compat_ptr(regs->gprs[4]), regs); | ||
460 | if (rc) { | ||
461 | result = rc; | ||
462 | goto out_putname; | ||
463 | } | ||
464 | current->thread.fp_regs.fpc=0; | 460 | current->thread.fp_regs.fpc=0; |
465 | asm volatile("sfpc %0,0" : : "d" (0)); | 461 | asm volatile("sfpc %0,0" : : "d" (0)); |
466 | result = regs->gprs[2]; | 462 | rc = regs->gprs[2]; |
467 | out_putname: | ||
468 | putname(filename); | ||
469 | out: | 463 | out: |
470 | return result; | 464 | putname(filename); |
471 | } | 465 | return rc; |
472 | |||
473 | |||
474 | #ifdef CONFIG_MODULES | ||
475 | |||
476 | asmlinkage long | ||
477 | sys32_init_module(void __user *umod, unsigned long len, | ||
478 | const char __user *uargs) | ||
479 | { | ||
480 | return sys_init_module(umod, len, uargs); | ||
481 | } | ||
482 | |||
483 | asmlinkage long | ||
484 | sys32_delete_module(const char __user *name_user, unsigned int flags) | ||
485 | { | ||
486 | return sys_delete_module(name_user, flags); | ||
487 | } | ||
488 | |||
489 | #else /* CONFIG_MODULES */ | ||
490 | |||
491 | asmlinkage long | ||
492 | sys32_init_module(void __user *umod, unsigned long len, | ||
493 | const char __user *uargs) | ||
494 | { | ||
495 | return -ENOSYS; | ||
496 | } | 466 | } |
497 | 467 | ||
498 | asmlinkage long | ||
499 | sys32_delete_module(const char __user *name_user, unsigned int flags) | ||
500 | { | ||
501 | return -ENOSYS; | ||
502 | } | ||
503 | |||
504 | #endif /* CONFIG_MODULES */ | ||
505 | |||
506 | asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, | 468 | asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, |
507 | size_t count, u32 poshi, u32 poslo) | 469 | size_t count, u32 poshi, u32 poslo) |
508 | { | 470 | { |
@@ -801,23 +763,6 @@ asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count) | |||
801 | return sys_write(fd, buf, count); | 763 | return sys_write(fd, buf, count); |
802 | } | 764 | } |
803 | 765 | ||
804 | asmlinkage long sys32_clone(void) | ||
805 | { | ||
806 | struct pt_regs *regs = task_pt_regs(current); | ||
807 | unsigned long clone_flags; | ||
808 | unsigned long newsp; | ||
809 | int __user *parent_tidptr, *child_tidptr; | ||
810 | |||
811 | clone_flags = regs->gprs[3] & 0xffffffffUL; | ||
812 | newsp = regs->orig_gpr2 & 0x7fffffffUL; | ||
813 | parent_tidptr = compat_ptr(regs->gprs[4]); | ||
814 | child_tidptr = compat_ptr(regs->gprs[5]); | ||
815 | if (!newsp) | ||
816 | newsp = regs->gprs[15]; | ||
817 | return do_fork(clone_flags, newsp, regs, 0, | ||
818 | parent_tidptr, child_tidptr); | ||
819 | } | ||
820 | |||
821 | /* | 766 | /* |
822 | * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64. | 767 | * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64. |
823 | * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE} | 768 | * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE} |
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 836a28842900..c07f9ca05ade 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h | |||
@@ -198,7 +198,8 @@ long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, | |||
198 | compat_sigset_t __user *oset, size_t sigsetsize); | 198 | compat_sigset_t __user *oset, size_t sigsetsize); |
199 | long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize); | 199 | long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize); |
200 | long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo); | 200 | long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo); |
201 | long sys32_execve(void); | 201 | long sys32_execve(char __user *name, compat_uptr_t __user *argv, |
202 | compat_uptr_t __user *envp); | ||
202 | long sys32_init_module(void __user *umod, unsigned long len, | 203 | long sys32_init_module(void __user *umod, unsigned long len, |
203 | const char __user *uargs); | 204 | const char __user *uargs); |
204 | long sys32_delete_module(const char __user *name_user, unsigned int flags); | 205 | long sys32_delete_module(const char __user *name_user, unsigned int flags); |
@@ -222,7 +223,6 @@ unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg); | |||
222 | long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg); | 223 | long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg); |
223 | long sys32_read(unsigned int fd, char __user * buf, size_t count); | 224 | long sys32_read(unsigned int fd, char __user * buf, size_t count); |
224 | long sys32_write(unsigned int fd, char __user * buf, size_t count); | 225 | long sys32_write(unsigned int fd, char __user * buf, size_t count); |
225 | long sys32_clone(void); | ||
226 | long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise); | 226 | long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise); |
227 | long sys32_fadvise64_64(struct fadvise64_64_args __user *args); | 227 | long sys32_fadvise64_64(struct fadvise64_64_args __user *args); |
228 | long sys32_sigaction(int sig, const struct old_sigaction32 __user *act, | 228 | long sys32_sigaction(int sig, const struct old_sigaction32 __user *act, |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 624790042d41..682fb69dba21 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -568,18 +568,18 @@ compat_sys_sigprocmask_wrapper: | |||
568 | llgtr %r4,%r4 # compat_old_sigset_t * | 568 | llgtr %r4,%r4 # compat_old_sigset_t * |
569 | jg compat_sys_sigprocmask # branch to system call | 569 | jg compat_sys_sigprocmask # branch to system call |
570 | 570 | ||
571 | .globl sys32_init_module_wrapper | 571 | .globl sys_init_module_wrapper |
572 | sys32_init_module_wrapper: | 572 | sys_init_module_wrapper: |
573 | llgtr %r2,%r2 # void * | 573 | llgtr %r2,%r2 # void * |
574 | llgfr %r3,%r3 # unsigned long | 574 | llgfr %r3,%r3 # unsigned long |
575 | llgtr %r4,%r4 # char * | 575 | llgtr %r4,%r4 # char * |
576 | jg sys32_init_module # branch to system call | 576 | jg sys_init_module # branch to system call |
577 | 577 | ||
578 | .globl sys32_delete_module_wrapper | 578 | .globl sys_delete_module_wrapper |
579 | sys32_delete_module_wrapper: | 579 | sys_delete_module_wrapper: |
580 | llgtr %r2,%r2 # const char * | 580 | llgtr %r2,%r2 # const char * |
581 | llgfr %r3,%r3 # unsigned int | 581 | llgfr %r3,%r3 # unsigned int |
582 | jg sys32_delete_module # branch to system call | 582 | jg sys_delete_module # branch to system call |
583 | 583 | ||
584 | .globl sys32_quotactl_wrapper | 584 | .globl sys32_quotactl_wrapper |
585 | sys32_quotactl_wrapper: | 585 | sys32_quotactl_wrapper: |
@@ -1840,3 +1840,18 @@ sys_perf_event_open_wrapper: | |||
1840 | lgfr %r5,%r5 # int | 1840 | lgfr %r5,%r5 # int |
1841 | llgfr %r6,%r6 # unsigned long | 1841 | llgfr %r6,%r6 # unsigned long |
1842 | jg sys_perf_event_open # branch to system call | 1842 | jg sys_perf_event_open # branch to system call |
1843 | |||
1844 | .globl sys_clone_wrapper | ||
1845 | sys_clone_wrapper: | ||
1846 | llgfr %r2,%r2 # unsigned long | ||
1847 | llgfr %r3,%r3 # unsigned long | ||
1848 | llgtr %r4,%r4 # int * | ||
1849 | llgtr %r5,%r5 # int * | ||
1850 | jg sys_clone # branch to system call | ||
1851 | |||
1852 | .globl sys32_execve_wrapper | ||
1853 | sys32_execve_wrapper: | ||
1854 | llgtr %r2,%r2 # char * | ||
1855 | llgtr %r3,%r3 # compat_uptr_t * | ||
1856 | llgtr %r4,%r4 # compat_uptr_t * | ||
1857 | jg sys32_execve # branch to system call | ||
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 950c59c6688b..e1e5e767ab56 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -42,10 +42,12 @@ long sys_s390_fadvise64_64(struct fadvise64_64_args __user *args); | |||
42 | long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, | 42 | long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, |
43 | u32 len_low); | 43 | u32 len_low); |
44 | long sys_fork(void); | 44 | long sys_fork(void); |
45 | long sys_clone(void); | 45 | long sys_clone(unsigned long newsp, unsigned long clone_flags, |
46 | int __user *parent_tidptr, int __user *child_tidptr); | ||
46 | long sys_vfork(void); | 47 | long sys_vfork(void); |
47 | void execve_tail(void); | 48 | void execve_tail(void); |
48 | long sys_execve(void); | 49 | long sys_execve(char __user *name, char __user * __user *argv, |
50 | char __user * __user *envp); | ||
49 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask); | 51 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask); |
50 | long sys_sigaction(int sig, const struct old_sigaction __user *act, | 52 | long sys_sigaction(int sig, const struct old_sigaction __user *act, |
51 | struct old_sigaction __user *oact); | 53 | struct old_sigaction __user *oact); |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 5a43f27eec13..59fe6ecc6ed3 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/elfcore.h> | 32 | #include <linux/elfcore.h> |
33 | #include <linux/kernel_stat.h> | 33 | #include <linux/kernel_stat.h> |
34 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
35 | #include <linux/compat.h> | ||
35 | #include <asm/compat.h> | 36 | #include <asm/compat.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
@@ -230,17 +231,11 @@ SYSCALL_DEFINE0(fork) | |||
230 | return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); | 231 | return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); |
231 | } | 232 | } |
232 | 233 | ||
233 | SYSCALL_DEFINE0(clone) | 234 | SYSCALL_DEFINE4(clone, unsigned long, newsp, unsigned long, clone_flags, |
235 | int __user *, parent_tidptr, int __user *, child_tidptr) | ||
234 | { | 236 | { |
235 | struct pt_regs *regs = task_pt_regs(current); | 237 | struct pt_regs *regs = task_pt_regs(current); |
236 | unsigned long clone_flags; | ||
237 | unsigned long newsp; | ||
238 | int __user *parent_tidptr, *child_tidptr; | ||
239 | 238 | ||
240 | clone_flags = regs->gprs[3]; | ||
241 | newsp = regs->orig_gpr2; | ||
242 | parent_tidptr = (int __user *) regs->gprs[4]; | ||
243 | child_tidptr = (int __user *) regs->gprs[5]; | ||
244 | if (!newsp) | 239 | if (!newsp) |
245 | newsp = regs->gprs[15]; | 240 | newsp = regs->gprs[15]; |
246 | return do_fork(clone_flags, newsp, regs, 0, | 241 | return do_fork(clone_flags, newsp, regs, 0, |
@@ -274,30 +269,25 @@ asmlinkage void execve_tail(void) | |||
274 | /* | 269 | /* |
275 | * sys_execve() executes a new program. | 270 | * sys_execve() executes a new program. |
276 | */ | 271 | */ |
277 | SYSCALL_DEFINE0(execve) | 272 | SYSCALL_DEFINE3(execve, char __user *, name, char __user * __user *, argv, |
273 | char __user * __user *, envp) | ||
278 | { | 274 | { |
279 | struct pt_regs *regs = task_pt_regs(current); | 275 | struct pt_regs *regs = task_pt_regs(current); |
280 | char *filename; | 276 | char *filename; |
281 | unsigned long result; | 277 | long rc; |
282 | int rc; | ||
283 | 278 | ||
284 | filename = getname((char __user *) regs->orig_gpr2); | 279 | filename = getname(name); |
285 | if (IS_ERR(filename)) { | 280 | rc = PTR_ERR(filename); |
286 | result = PTR_ERR(filename); | 281 | if (IS_ERR(filename)) |
282 | return rc; | ||
283 | rc = do_execve(filename, argv, envp, regs); | ||
284 | if (rc) | ||
287 | goto out; | 285 | goto out; |
288 | } | ||
289 | rc = do_execve(filename, (char __user * __user *) regs->gprs[3], | ||
290 | (char __user * __user *) regs->gprs[4], regs); | ||
291 | if (rc) { | ||
292 | result = rc; | ||
293 | goto out_putname; | ||
294 | } | ||
295 | execve_tail(); | 286 | execve_tail(); |
296 | result = regs->gprs[2]; | 287 | rc = regs->gprs[2]; |
297 | out_putname: | ||
298 | putname(filename); | ||
299 | out: | 288 | out: |
300 | return result; | 289 | putname(filename); |
290 | return rc; | ||
301 | } | 291 | } |
302 | 292 | ||
303 | /* | 293 | /* |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index f3ddd7ac06c5..a8738676b26c 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -339,24 +339,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
339 | int copied, ret; | 339 | int copied, ret; |
340 | 340 | ||
341 | switch (request) { | 341 | switch (request) { |
342 | case PTRACE_PEEKTEXT: | ||
343 | case PTRACE_PEEKDATA: | ||
344 | /* Remove high order bit from address (only for 31 bit). */ | ||
345 | addr &= PSW_ADDR_INSN; | ||
346 | /* read word at location addr. */ | ||
347 | return generic_ptrace_peekdata(child, addr, data); | ||
348 | |||
349 | case PTRACE_PEEKUSR: | 342 | case PTRACE_PEEKUSR: |
350 | /* read the word at location addr in the USER area. */ | 343 | /* read the word at location addr in the USER area. */ |
351 | return peek_user(child, addr, data); | 344 | return peek_user(child, addr, data); |
352 | 345 | ||
353 | case PTRACE_POKETEXT: | ||
354 | case PTRACE_POKEDATA: | ||
355 | /* Remove high order bit from address (only for 31 bit). */ | ||
356 | addr &= PSW_ADDR_INSN; | ||
357 | /* write the word at location addr. */ | ||
358 | return generic_ptrace_pokedata(child, addr, data); | ||
359 | |||
360 | case PTRACE_POKEUSR: | 346 | case PTRACE_POKEUSR: |
361 | /* write the word at location addr in the USER area */ | 347 | /* write the word at location addr in the USER area */ |
362 | return poke_user(child, addr, data); | 348 | return poke_user(child, addr, data); |
@@ -386,8 +372,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
386 | copied += sizeof(unsigned long); | 372 | copied += sizeof(unsigned long); |
387 | } | 373 | } |
388 | return 0; | 374 | return 0; |
375 | default: | ||
376 | /* Removing high order bit from addr (only for 31 bit). */ | ||
377 | addr &= PSW_ADDR_INSN; | ||
378 | return ptrace_request(child, request, addr, data); | ||
389 | } | 379 | } |
390 | return ptrace_request(child, request, addr, data); | ||
391 | } | 380 | } |
392 | 381 | ||
393 | #ifdef CONFIG_COMPAT | 382 | #ifdef CONFIG_COMPAT |
diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index 20639dfe0c42..e27ca63076d1 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S | |||
@@ -24,8 +24,6 @@ LC_EXT_INT_CODE = 0x86 # addr of ext int code | |||
24 | # R3 = external interruption parameter if R2=0 | 24 | # R3 = external interruption parameter if R2=0 |
25 | # | 25 | # |
26 | 26 | ||
27 | .section ".init.text","ax" | ||
28 | |||
29 | _sclp_wait_int: | 27 | _sclp_wait_int: |
30 | stm %r6,%r15,24(%r15) # save registers | 28 | stm %r6,%r15,24(%r15) # save registers |
31 | basr %r13,0 # get base register | 29 | basr %r13,0 # get base register |
@@ -318,9 +316,8 @@ _sclp_print_early: | |||
318 | .long _sclp_work_area | 316 | .long _sclp_work_area |
319 | .Lascebc: | 317 | .Lascebc: |
320 | .long _ascebc | 318 | .long _ascebc |
321 | .previous | ||
322 | 319 | ||
323 | .section ".init.data","a" | 320 | .section .data,"aw",@progbits |
324 | .balign 4096 | 321 | .balign 4096 |
325 | _sclp_work_area: | 322 | _sclp_work_area: |
326 | .fill 4096 | 323 | .fill 4096 |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 56c16876b919..b4b6396e6cf0 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -475,10 +475,8 @@ static int __cpuinit smp_alloc_lowcore(int cpu) | |||
475 | { | 475 | { |
476 | unsigned long async_stack, panic_stack; | 476 | unsigned long async_stack, panic_stack; |
477 | struct _lowcore *lowcore; | 477 | struct _lowcore *lowcore; |
478 | int lc_order; | ||
479 | 478 | ||
480 | lc_order = sizeof(long) == 8 ? 1 : 0; | 479 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); |
481 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); | ||
482 | if (!lowcore) | 480 | if (!lowcore) |
483 | return -ENOMEM; | 481 | return -ENOMEM; |
484 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); | 482 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); |
@@ -509,16 +507,14 @@ static int __cpuinit smp_alloc_lowcore(int cpu) | |||
509 | out: | 507 | out: |
510 | free_page(panic_stack); | 508 | free_page(panic_stack); |
511 | free_pages(async_stack, ASYNC_ORDER); | 509 | free_pages(async_stack, ASYNC_ORDER); |
512 | free_pages((unsigned long) lowcore, lc_order); | 510 | free_pages((unsigned long) lowcore, LC_ORDER); |
513 | return -ENOMEM; | 511 | return -ENOMEM; |
514 | } | 512 | } |
515 | 513 | ||
516 | static void smp_free_lowcore(int cpu) | 514 | static void smp_free_lowcore(int cpu) |
517 | { | 515 | { |
518 | struct _lowcore *lowcore; | 516 | struct _lowcore *lowcore; |
519 | int lc_order; | ||
520 | 517 | ||
521 | lc_order = sizeof(long) == 8 ? 1 : 0; | ||
522 | lowcore = lowcore_ptr[cpu]; | 518 | lowcore = lowcore_ptr[cpu]; |
523 | #ifndef CONFIG_64BIT | 519 | #ifndef CONFIG_64BIT |
524 | if (MACHINE_HAS_IEEE) | 520 | if (MACHINE_HAS_IEEE) |
@@ -528,7 +524,7 @@ static void smp_free_lowcore(int cpu) | |||
528 | #endif | 524 | #endif |
529 | free_page(lowcore->panic_stack - PAGE_SIZE); | 525 | free_page(lowcore->panic_stack - PAGE_SIZE); |
530 | free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); | 526 | free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); |
531 | free_pages((unsigned long) lowcore, lc_order); | 527 | free_pages((unsigned long) lowcore, LC_ORDER); |
532 | lowcore_ptr[cpu] = NULL; | 528 | lowcore_ptr[cpu] = NULL; |
533 | } | 529 | } |
534 | 530 | ||
@@ -664,7 +660,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
664 | unsigned long async_stack, panic_stack; | 660 | unsigned long async_stack, panic_stack; |
665 | struct _lowcore *lowcore; | 661 | struct _lowcore *lowcore; |
666 | unsigned int cpu; | 662 | unsigned int cpu; |
667 | int lc_order; | ||
668 | 663 | ||
669 | smp_detect_cpus(); | 664 | smp_detect_cpus(); |
670 | 665 | ||
@@ -674,8 +669,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
674 | print_cpu_info(); | 669 | print_cpu_info(); |
675 | 670 | ||
676 | /* Reallocate current lowcore, but keep its contents. */ | 671 | /* Reallocate current lowcore, but keep its contents. */ |
677 | lc_order = sizeof(long) == 8 ? 1 : 0; | 672 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); |
678 | lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); | ||
679 | panic_stack = __get_free_page(GFP_KERNEL); | 673 | panic_stack = __get_free_page(GFP_KERNEL); |
680 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); | 674 | async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); |
681 | BUG_ON(!lowcore || !panic_stack || !async_stack); | 675 | BUG_ON(!lowcore || !panic_stack || !async_stack); |
@@ -1047,42 +1041,6 @@ out: | |||
1047 | static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, | 1041 | static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, |
1048 | dispatching_store); | 1042 | dispatching_store); |
1049 | 1043 | ||
1050 | /* | ||
1051 | * If the resume kernel runs on another cpu than the suspended kernel, | ||
1052 | * we have to switch the cpu IDs in the logical map. | ||
1053 | */ | ||
1054 | void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id, | ||
1055 | struct _lowcore *suspend_lowcore) | ||
1056 | { | ||
1057 | int cpu, suspend_cpu_id, resume_cpu_id; | ||
1058 | u32 suspend_phys_cpu_id; | ||
1059 | |||
1060 | suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr]; | ||
1061 | suspend_cpu_id = suspend_lowcore->cpu_nr; | ||
1062 | |||
1063 | for_each_present_cpu(cpu) { | ||
1064 | if (__cpu_logical_map[cpu] == resume_phys_cpu_id) { | ||
1065 | resume_cpu_id = cpu; | ||
1066 | goto found; | ||
1067 | } | ||
1068 | } | ||
1069 | panic("Could not find resume cpu in logical map.\n"); | ||
1070 | |||
1071 | found: | ||
1072 | printk("Resume cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id); | ||
1073 | printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id); | ||
1074 | |||
1075 | __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id; | ||
1076 | __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id; | ||
1077 | |||
1078 | lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id; | ||
1079 | } | ||
1080 | |||
1081 | u32 smp_get_phys_cpu_id(void) | ||
1082 | { | ||
1083 | return __cpu_logical_map[smp_processor_id()]; | ||
1084 | } | ||
1085 | |||
1086 | static int __init topology_init(void) | 1044 | static int __init topology_init(void) |
1087 | { | 1045 | { |
1088 | int cpu; | 1046 | int cpu; |
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c index 086bee970cae..cf9e5c6d5527 100644 --- a/arch/s390/kernel/suspend.c +++ b/arch/s390/kernel/suspend.c | |||
@@ -6,36 +6,26 @@ | |||
6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> | 6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/suspend.h> | ||
10 | #include <linux/reboot.h> | ||
11 | #include <linux/pfn.h> | 9 | #include <linux/pfn.h> |
12 | #include <linux/mm.h> | ||
13 | #include <asm/sections.h> | ||
14 | #include <asm/system.h> | 10 | #include <asm/system.h> |
15 | #include <asm/ipl.h> | ||
16 | 11 | ||
17 | /* | 12 | /* |
18 | * References to section boundaries | 13 | * References to section boundaries |
19 | */ | 14 | */ |
20 | extern const void __nosave_begin, __nosave_end; | 15 | extern const void __nosave_begin, __nosave_end; |
21 | 16 | ||
22 | /* | ||
23 | * check if given pfn is in the 'nosave' or in the read only NSS section | ||
24 | */ | ||
25 | int pfn_is_nosave(unsigned long pfn) | 17 | int pfn_is_nosave(unsigned long pfn) |
26 | { | 18 | { |
27 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; | 19 | unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); |
28 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) | 20 | unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end)); |
29 | >> PAGE_SHIFT; | ||
30 | unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; | ||
31 | unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); | ||
32 | 21 | ||
22 | /* Always save lowcore pages (LC protection might be enabled). */ | ||
23 | if (pfn <= LC_PAGES) | ||
24 | return 0; | ||
33 | if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) | 25 | if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) |
34 | return 1; | 26 | return 1; |
35 | if (pfn >= stext_pfn && pfn <= eshared_pfn) { | 27 | /* Skip memory holes and read-only pages (NSS, DCSS, ...). */ |
36 | if (ipl_info.type == IPL_TYPE_NSS) | 28 | if (tprot(PFN_PHYS(pfn))) |
37 | return 1; | ||
38 | } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) | ||
39 | return 1; | 29 | return 1; |
40 | return 0; | 30 | return 0; |
41 | } | 31 | } |
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 7cd6b096f0d1..fe927d0bc20b 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include <asm/page.h> | 10 | #include <asm/page.h> |
11 | #include <asm/ptrace.h> | 11 | #include <asm/ptrace.h> |
12 | #include <asm/thread_info.h> | ||
12 | #include <asm/asm-offsets.h> | 13 | #include <asm/asm-offsets.h> |
13 | 14 | ||
14 | /* | 15 | /* |
@@ -41,6 +42,9 @@ swsusp_arch_suspend: | |||
41 | /* Get pointer to save area */ | 42 | /* Get pointer to save area */ |
42 | lghi %r1,0x1000 | 43 | lghi %r1,0x1000 |
43 | 44 | ||
45 | /* Save CPU address */ | ||
46 | stap __LC_CPU_ADDRESS(%r1) | ||
47 | |||
44 | /* Store registers */ | 48 | /* Store registers */ |
45 | mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ | 49 | mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ |
46 | stfpc 0x31c(%r1) /* store fpu control */ | 50 | stfpc 0x31c(%r1) /* store fpu control */ |
@@ -102,11 +106,10 @@ swsusp_arch_resume: | |||
102 | aghi %r15,-STACK_FRAME_OVERHEAD | 106 | aghi %r15,-STACK_FRAME_OVERHEAD |
103 | stg %r1,__SF_BACKCHAIN(%r15) | 107 | stg %r1,__SF_BACKCHAIN(%r15) |
104 | 108 | ||
105 | #ifdef CONFIG_SMP | 109 | /* Make all free pages stable */ |
106 | /* Save boot cpu number */ | 110 | lghi %r2,1 |
107 | brasl %r14,smp_get_phys_cpu_id | 111 | brasl %r14,arch_set_page_states |
108 | lgr %r10,%r2 | 112 | |
109 | #endif | ||
110 | /* Deactivate DAT */ | 113 | /* Deactivate DAT */ |
111 | stnsm __SF_EMPTY(%r15),0xfb | 114 | stnsm __SF_EMPTY(%r15),0xfb |
112 | 115 | ||
@@ -133,6 +136,69 @@ swsusp_arch_resume: | |||
133 | 2: | 136 | 2: |
134 | ptlb /* flush tlb */ | 137 | ptlb /* flush tlb */ |
135 | 138 | ||
139 | /* Reset System */ | ||
140 | larl %r1,restart_entry | ||
141 | larl %r2,.Lrestart_diag308_psw | ||
142 | og %r1,0(%r2) | ||
143 | stg %r1,0(%r0) | ||
144 | larl %r1,.Lnew_pgm_check_psw | ||
145 | epsw %r2,%r3 | ||
146 | stm %r2,%r3,0(%r1) | ||
147 | mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) | ||
148 | lghi %r0,0 | ||
149 | diag %r0,%r0,0x308 | ||
150 | restart_entry: | ||
151 | lhi %r1,1 | ||
152 | sigp %r1,%r0,0x12 | ||
153 | sam64 | ||
154 | larl %r1,.Lnew_pgm_check_psw | ||
155 | lpswe 0(%r1) | ||
156 | pgm_check_entry: | ||
157 | |||
158 | /* Switch to original suspend CPU */ | ||
159 | larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ | ||
160 | stap 0(%r1) | ||
161 | llgh %r2,0(%r1) | ||
162 | lghi %r3,0x1000 | ||
163 | llgh %r1,__LC_CPU_ADDRESS(%r3) /* Suspend CPU address: r1 */ | ||
164 | cgr %r1,%r2 | ||
165 | je restore_registers /* r1 = r2 -> nothing to do */ | ||
166 | larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ | ||
167 | mvc __LC_RESTART_PSW(16,%r0),0(%r4) | ||
168 | 3: | ||
169 | sigp %r9,%r1,__SIGP_INITIAL_CPU_RESET | ||
170 | brc 8,4f /* accepted */ | ||
171 | brc 2,3b /* busy, try again */ | ||
172 | |||
173 | /* Suspend CPU not available -> panic */ | ||
174 | larl %r15,init_thread_union | ||
175 | ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) | ||
176 | larl %r2,.Lpanic_string | ||
177 | larl %r3,_sclp_print_early | ||
178 | lghi %r1,0 | ||
179 | sam31 | ||
180 | sigp %r1,%r0,0x12 | ||
181 | basr %r14,%r3 | ||
182 | larl %r3,.Ldisabled_wait_31 | ||
183 | lpsw 0(%r3) | ||
184 | 4: | ||
185 | /* Switch to suspend CPU */ | ||
186 | sigp %r9,%r1,__SIGP_RESTART /* start suspend CPU */ | ||
187 | brc 2,4b /* busy, try again */ | ||
188 | 5: | ||
189 | sigp %r9,%r2,__SIGP_STOP /* stop resume (current) CPU */ | ||
190 | 6: j 6b | ||
191 | |||
192 | restart_suspend: | ||
193 | larl %r1,.Lresume_cpu | ||
194 | llgh %r2,0(%r1) | ||
195 | 7: | ||
196 | sigp %r9,%r2,__SIGP_SENSE /* Wait for resume CPU */ | ||
197 | brc 2,7b /* busy, try again */ | ||
198 | tmll %r9,0x40 /* Test if resume CPU is stopped */ | ||
199 | jz 7b | ||
200 | |||
201 | restore_registers: | ||
136 | /* Restore registers */ | 202 | /* Restore registers */ |
137 | lghi %r13,0x1000 /* %r1 = pointer to save arae */ | 203 | lghi %r13,0x1000 /* %r1 = pointer to save arae */ |
138 | 204 | ||
@@ -166,19 +232,33 @@ swsusp_arch_resume: | |||
166 | /* Pointer to save area */ | 232 | /* Pointer to save area */ |
167 | lghi %r13,0x1000 | 233 | lghi %r13,0x1000 |
168 | 234 | ||
169 | #ifdef CONFIG_SMP | ||
170 | /* Switch CPUs */ | ||
171 | lgr %r2,%r10 /* get cpu id */ | ||
172 | llgf %r3,0x318(%r13) | ||
173 | brasl %r14,smp_switch_boot_cpu_in_resume | ||
174 | #endif | ||
175 | /* Restore prefix register */ | 235 | /* Restore prefix register */ |
176 | spx 0x318(%r13) | 236 | spx 0x318(%r13) |
177 | 237 | ||
178 | /* Activate DAT */ | 238 | /* Activate DAT */ |
179 | stosm __SF_EMPTY(%r15),0x04 | 239 | stosm __SF_EMPTY(%r15),0x04 |
180 | 240 | ||
241 | /* Make all free pages unstable */ | ||
242 | lghi %r2,0 | ||
243 | brasl %r14,arch_set_page_states | ||
244 | |||
181 | /* Return 0 */ | 245 | /* Return 0 */ |
182 | lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) | 246 | lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) |
183 | lghi %r2,0 | 247 | lghi %r2,0 |
184 | br %r14 | 248 | br %r14 |
249 | |||
250 | .section .data.nosave,"aw",@progbits | ||
251 | .align 8 | ||
252 | .Ldisabled_wait_31: | ||
253 | .long 0x000a0000,0x00000000 | ||
254 | .Lpanic_string: | ||
255 | .asciz "Resume not possible because suspend CPU is no longer available" | ||
256 | .align 8 | ||
257 | .Lrestart_diag308_psw: | ||
258 | .long 0x00080000,0x80000000 | ||
259 | .Lrestart_suspend_psw: | ||
260 | .quad 0x0000000180000000,restart_suspend | ||
261 | .Lnew_pgm_check_psw: | ||
262 | .quad 0,pgm_check_entry | ||
263 | .Lresume_cpu: | ||
264 | .byte 0,0 | ||
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 0b5083681e77..30eca070d426 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -19,7 +19,7 @@ SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall) | |||
19 | SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper) | 19 | SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper) |
20 | SYSCALL(sys_link,sys_link,sys32_link_wrapper) | 20 | SYSCALL(sys_link,sys_link,sys32_link_wrapper) |
21 | SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */ | 21 | SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */ |
22 | SYSCALL(sys_execve,sys_execve,sys32_execve) | 22 | SYSCALL(sys_execve,sys_execve,sys32_execve_wrapper) |
23 | SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper) | 23 | SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper) |
24 | SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */ | 24 | SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */ |
25 | SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper) | 25 | SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper) |
@@ -128,7 +128,7 @@ SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) | |||
128 | SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) | 128 | SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) |
129 | SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) | 129 | SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) |
130 | SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) | 130 | SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) |
131 | SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */ | 131 | SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */ |
132 | SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) | 132 | SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) |
133 | SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper) | 133 | SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper) |
134 | NI_SYSCALL /* modify_ldt for i386 */ | 134 | NI_SYSCALL /* modify_ldt for i386 */ |
@@ -136,8 +136,8 @@ SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper) | |||
136 | SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */ | 136 | SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */ |
137 | SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper) | 137 | SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper) |
138 | NI_SYSCALL /* old "create module" */ | 138 | NI_SYSCALL /* old "create module" */ |
139 | SYSCALL(sys_init_module,sys_init_module,sys32_init_module_wrapper) | 139 | SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper) |
140 | SYSCALL(sys_delete_module,sys_delete_module,sys32_delete_module_wrapper) | 140 | SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper) |
141 | NI_SYSCALL /* 130: old get_kernel_syms */ | 141 | NI_SYSCALL /* 130: old get_kernel_syms */ |
142 | SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper) | 142 | SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper) |
143 | SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper) | 143 | SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper) |
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index f92ec203ad92..098923ae458f 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c | |||
@@ -50,28 +50,64 @@ void __init cmma_init(void) | |||
50 | cmma_flag = 0; | 50 | cmma_flag = 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | void arch_free_page(struct page *page, int order) | 53 | static inline void set_page_unstable(struct page *page, int order) |
54 | { | 54 | { |
55 | int i, rc; | 55 | int i, rc; |
56 | 56 | ||
57 | if (!cmma_flag) | ||
58 | return; | ||
59 | for (i = 0; i < (1 << order); i++) | 57 | for (i = 0; i < (1 << order); i++) |
60 | asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" | 58 | asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" |
61 | : "=&d" (rc) | 59 | : "=&d" (rc) |
62 | : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), | 60 | : "a" (page_to_phys(page + i)), |
63 | "i" (ESSA_SET_UNUSED)); | 61 | "i" (ESSA_SET_UNUSED)); |
64 | } | 62 | } |
65 | 63 | ||
66 | void arch_alloc_page(struct page *page, int order) | 64 | void arch_free_page(struct page *page, int order) |
67 | { | 65 | { |
68 | int i, rc; | ||
69 | |||
70 | if (!cmma_flag) | 66 | if (!cmma_flag) |
71 | return; | 67 | return; |
68 | set_page_unstable(page, order); | ||
69 | } | ||
70 | |||
71 | static inline void set_page_stable(struct page *page, int order) | ||
72 | { | ||
73 | int i, rc; | ||
74 | |||
72 | for (i = 0; i < (1 << order); i++) | 75 | for (i = 0; i < (1 << order); i++) |
73 | asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" | 76 | asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0" |
74 | : "=&d" (rc) | 77 | : "=&d" (rc) |
75 | : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT), | 78 | : "a" (page_to_phys(page + i)), |
76 | "i" (ESSA_SET_STABLE)); | 79 | "i" (ESSA_SET_STABLE)); |
77 | } | 80 | } |
81 | |||
82 | void arch_alloc_page(struct page *page, int order) | ||
83 | { | ||
84 | if (!cmma_flag) | ||
85 | return; | ||
86 | set_page_stable(page, order); | ||
87 | } | ||
88 | |||
89 | void arch_set_page_states(int make_stable) | ||
90 | { | ||
91 | unsigned long flags, order, t; | ||
92 | struct list_head *l; | ||
93 | struct page *page; | ||
94 | struct zone *zone; | ||
95 | |||
96 | if (!cmma_flag) | ||
97 | return; | ||
98 | if (make_stable) | ||
99 | drain_local_pages(NULL); | ||
100 | for_each_populated_zone(zone) { | ||
101 | spin_lock_irqsave(&zone->lock, flags); | ||
102 | for_each_migratetype_order(order, t) { | ||
103 | list_for_each(l, &zone->free_area[order].free_list[t]) { | ||
104 | page = list_entry(l, struct page, lru); | ||
105 | if (make_stable) | ||
106 | set_page_stable(page, order); | ||
107 | else | ||
108 | set_page_unstable(page, order); | ||
109 | } | ||
110 | } | ||
111 | spin_unlock_irqrestore(&zone->lock, flags); | ||
112 | } | ||
113 | } | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index c70215247071..c60bfb309ce6 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -314,21 +314,18 @@ int s390_enable_sie(void) | |||
314 | } | 314 | } |
315 | EXPORT_SYMBOL_GPL(s390_enable_sie); | 315 | EXPORT_SYMBOL_GPL(s390_enable_sie); |
316 | 316 | ||
317 | #ifdef CONFIG_DEBUG_PAGEALLOC | 317 | #if defined(CONFIG_DEBUG_PAGEALLOC) && defined(CONFIG_HIBERNATION) |
318 | #ifdef CONFIG_HIBERNATION | ||
319 | bool kernel_page_present(struct page *page) | 318 | bool kernel_page_present(struct page *page) |
320 | { | 319 | { |
321 | unsigned long addr; | 320 | unsigned long addr; |
322 | int cc; | 321 | int cc; |
323 | 322 | ||
324 | addr = page_to_phys(page); | 323 | addr = page_to_phys(page); |
325 | asm("lra %1,0(%1)\n" | 324 | asm volatile( |
326 | "ipm %0\n" | 325 | " lra %1,0(%1)\n" |
327 | "srl %0,28" | 326 | " ipm %0\n" |
328 | :"=d"(cc),"+a"(addr)::"cc"); | 327 | " srl %0,28" |
328 | : "=d" (cc), "+a" (addr) : : "cc"); | ||
329 | return cc == 0; | 329 | return cc == 0; |
330 | } | 330 | } |
331 | 331 | #endif /* CONFIG_HIBERNATION && CONFIG_DEBUG_PAGEALLOC */ | |
332 | #endif /* CONFIG_HIBERNATION */ | ||
333 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
334 | |||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bd9fe2e36dce..ab3521755588 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -935,6 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) | |||
935 | struct dasd_eckd_private *private; | 935 | struct dasd_eckd_private *private; |
936 | 936 | ||
937 | private = (struct dasd_eckd_private *) device->private; | 937 | private = (struct dasd_eckd_private *) device->private; |
938 | memset(&private->features, 0, sizeof(struct dasd_rssd_features)); | ||
938 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, | 939 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, |
939 | (sizeof(struct dasd_psf_prssd_data) + | 940 | (sizeof(struct dasd_psf_prssd_data) + |
940 | sizeof(struct dasd_rssd_features)), | 941 | sizeof(struct dasd_rssd_features)), |
@@ -982,7 +983,9 @@ static int dasd_eckd_read_features(struct dasd_device *device) | |||
982 | features = (struct dasd_rssd_features *) (prssdp + 1); | 983 | features = (struct dasd_rssd_features *) (prssdp + 1); |
983 | memcpy(&private->features, features, | 984 | memcpy(&private->features, features, |
984 | sizeof(struct dasd_rssd_features)); | 985 | sizeof(struct dasd_rssd_features)); |
985 | } | 986 | } else |
987 | dev_warn(&device->cdev->dev, "Reading device feature codes" | ||
988 | " failed with rc=%d\n", rc); | ||
986 | dasd_sfree_request(cqr, cqr->memdev); | 989 | dasd_sfree_request(cqr, cqr->memdev); |
987 | return rc; | 990 | return rc; |
988 | } | 991 | } |
@@ -1144,9 +1147,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1144 | } | 1147 | } |
1145 | 1148 | ||
1146 | /* Read Feature Codes */ | 1149 | /* Read Feature Codes */ |
1147 | rc = dasd_eckd_read_features(device); | 1150 | dasd_eckd_read_features(device); |
1148 | if (rc) | ||
1149 | goto out_err3; | ||
1150 | 1151 | ||
1151 | /* Read Device Characteristics */ | 1152 | /* Read Device Characteristics */ |
1152 | rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, | 1153 | rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, |
@@ -3241,9 +3242,7 @@ int dasd_eckd_restore_device(struct dasd_device *device) | |||
3241 | } | 3242 | } |
3242 | 3243 | ||
3243 | /* Read Feature Codes */ | 3244 | /* Read Feature Codes */ |
3244 | rc = dasd_eckd_read_features(device); | 3245 | dasd_eckd_read_features(device); |
3245 | if (rc) | ||
3246 | goto out_err; | ||
3247 | 3246 | ||
3248 | /* Read Device Characteristics */ | 3247 | /* Read Device Characteristics */ |
3249 | memset(&private->rdc_data, 0, sizeof(private->rdc_data)); | 3248 | memset(&private->rdc_data, 0, sizeof(private->rdc_data)); |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 393c73c47f87..91c25706fa83 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -31,8 +31,7 @@ | |||
31 | #include "chp.h" | 31 | #include "chp.h" |
32 | 32 | ||
33 | int css_init_done = 0; | 33 | int css_init_done = 0; |
34 | static int need_reprobe = 0; | 34 | int max_ssid; |
35 | static int max_ssid = 0; | ||
36 | 35 | ||
37 | struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; | 36 | struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; |
38 | 37 | ||
@@ -315,12 +314,18 @@ int css_probe_device(struct subchannel_id schid) | |||
315 | int ret; | 314 | int ret; |
316 | struct subchannel *sch; | 315 | struct subchannel *sch; |
317 | 316 | ||
318 | sch = css_alloc_subchannel(schid); | 317 | if (cio_is_console(schid)) |
319 | if (IS_ERR(sch)) | 318 | sch = cio_get_console_subchannel(); |
320 | return PTR_ERR(sch); | 319 | else { |
320 | sch = css_alloc_subchannel(schid); | ||
321 | if (IS_ERR(sch)) | ||
322 | return PTR_ERR(sch); | ||
323 | } | ||
321 | ret = css_register_subchannel(sch); | 324 | ret = css_register_subchannel(sch); |
322 | if (ret) | 325 | if (ret) { |
323 | put_device(&sch->dev); | 326 | if (!cio_is_console(schid)) |
327 | put_device(&sch->dev); | ||
328 | } | ||
324 | return ret; | 329 | return ret; |
325 | } | 330 | } |
326 | 331 | ||
@@ -409,10 +414,14 @@ static void css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
409 | 414 | ||
410 | static struct idset *slow_subchannel_set; | 415 | static struct idset *slow_subchannel_set; |
411 | static spinlock_t slow_subchannel_lock; | 416 | static spinlock_t slow_subchannel_lock; |
417 | static wait_queue_head_t css_eval_wq; | ||
418 | static atomic_t css_eval_scheduled; | ||
412 | 419 | ||
413 | static int __init slow_subchannel_init(void) | 420 | static int __init slow_subchannel_init(void) |
414 | { | 421 | { |
415 | spin_lock_init(&slow_subchannel_lock); | 422 | spin_lock_init(&slow_subchannel_lock); |
423 | atomic_set(&css_eval_scheduled, 0); | ||
424 | init_waitqueue_head(&css_eval_wq); | ||
416 | slow_subchannel_set = idset_sch_new(); | 425 | slow_subchannel_set = idset_sch_new(); |
417 | if (!slow_subchannel_set) { | 426 | if (!slow_subchannel_set) { |
418 | CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n"); | 427 | CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n"); |
@@ -468,9 +477,17 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) | |||
468 | 477 | ||
469 | static void css_slow_path_func(struct work_struct *unused) | 478 | static void css_slow_path_func(struct work_struct *unused) |
470 | { | 479 | { |
480 | unsigned long flags; | ||
481 | |||
471 | CIO_TRACE_EVENT(4, "slowpath"); | 482 | CIO_TRACE_EVENT(4, "slowpath"); |
472 | for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn, | 483 | for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn, |
473 | NULL); | 484 | NULL); |
485 | spin_lock_irqsave(&slow_subchannel_lock, flags); | ||
486 | if (idset_is_empty(slow_subchannel_set)) { | ||
487 | atomic_set(&css_eval_scheduled, 0); | ||
488 | wake_up(&css_eval_wq); | ||
489 | } | ||
490 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); | ||
474 | } | 491 | } |
475 | 492 | ||
476 | static DECLARE_WORK(slow_path_work, css_slow_path_func); | 493 | static DECLARE_WORK(slow_path_work, css_slow_path_func); |
@@ -482,6 +499,7 @@ void css_schedule_eval(struct subchannel_id schid) | |||
482 | 499 | ||
483 | spin_lock_irqsave(&slow_subchannel_lock, flags); | 500 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
484 | idset_sch_add(slow_subchannel_set, schid); | 501 | idset_sch_add(slow_subchannel_set, schid); |
502 | atomic_set(&css_eval_scheduled, 1); | ||
485 | queue_work(slow_path_wq, &slow_path_work); | 503 | queue_work(slow_path_wq, &slow_path_work); |
486 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); | 504 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
487 | } | 505 | } |
@@ -492,80 +510,53 @@ void css_schedule_eval_all(void) | |||
492 | 510 | ||
493 | spin_lock_irqsave(&slow_subchannel_lock, flags); | 511 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
494 | idset_fill(slow_subchannel_set); | 512 | idset_fill(slow_subchannel_set); |
513 | atomic_set(&css_eval_scheduled, 1); | ||
495 | queue_work(slow_path_wq, &slow_path_work); | 514 | queue_work(slow_path_wq, &slow_path_work); |
496 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); | 515 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
497 | } | 516 | } |
498 | 517 | ||
499 | void css_wait_for_slow_path(void) | 518 | static int __unset_registered(struct device *dev, void *data) |
500 | { | 519 | { |
501 | flush_workqueue(slow_path_wq); | 520 | struct idset *set = data; |
502 | } | 521 | struct subchannel *sch = to_subchannel(dev); |
503 | |||
504 | /* Reprobe subchannel if unregistered. */ | ||
505 | static int reprobe_subchannel(struct subchannel_id schid, void *data) | ||
506 | { | ||
507 | int ret; | ||
508 | |||
509 | CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n", | ||
510 | schid.ssid, schid.sch_no); | ||
511 | if (need_reprobe) | ||
512 | return -EAGAIN; | ||
513 | |||
514 | ret = css_probe_device(schid); | ||
515 | switch (ret) { | ||
516 | case 0: | ||
517 | break; | ||
518 | case -ENXIO: | ||
519 | case -ENOMEM: | ||
520 | case -EIO: | ||
521 | /* These should abort looping */ | ||
522 | break; | ||
523 | default: | ||
524 | ret = 0; | ||
525 | } | ||
526 | |||
527 | return ret; | ||
528 | } | ||
529 | 522 | ||
530 | static void reprobe_after_idle(struct work_struct *unused) | 523 | idset_sch_del(set, sch->schid); |
531 | { | 524 | return 0; |
532 | /* Make sure initial subchannel scan is done. */ | ||
533 | wait_event(ccw_device_init_wq, | ||
534 | atomic_read(&ccw_device_init_count) == 0); | ||
535 | if (need_reprobe) | ||
536 | css_schedule_reprobe(); | ||
537 | } | 525 | } |
538 | 526 | ||
539 | static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); | 527 | void css_schedule_eval_all_unreg(void) |
540 | |||
541 | /* Work function used to reprobe all unregistered subchannels. */ | ||
542 | static void reprobe_all(struct work_struct *unused) | ||
543 | { | 528 | { |
544 | int ret; | 529 | unsigned long flags; |
545 | 530 | struct idset *unreg_set; | |
546 | CIO_MSG_EVENT(4, "reprobe start\n"); | ||
547 | 531 | ||
548 | /* Make sure initial subchannel scan is done. */ | 532 | /* Find unregistered subchannels. */ |
549 | if (atomic_read(&ccw_device_init_count) != 0) { | 533 | unreg_set = idset_sch_new(); |
550 | queue_work(ccw_device_work, &reprobe_idle_work); | 534 | if (!unreg_set) { |
535 | /* Fallback. */ | ||
536 | css_schedule_eval_all(); | ||
551 | return; | 537 | return; |
552 | } | 538 | } |
553 | need_reprobe = 0; | 539 | idset_fill(unreg_set); |
554 | ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); | 540 | bus_for_each_dev(&css_bus_type, NULL, unreg_set, __unset_registered); |
555 | 541 | /* Apply to slow_subchannel_set. */ | |
556 | CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, | 542 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
557 | need_reprobe); | 543 | idset_add_set(slow_subchannel_set, unreg_set); |
544 | atomic_set(&css_eval_scheduled, 1); | ||
545 | queue_work(slow_path_wq, &slow_path_work); | ||
546 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); | ||
547 | idset_free(unreg_set); | ||
558 | } | 548 | } |
559 | 549 | ||
560 | static DECLARE_WORK(css_reprobe_work, reprobe_all); | 550 | void css_wait_for_slow_path(void) |
551 | { | ||
552 | flush_workqueue(slow_path_wq); | ||
553 | } | ||
561 | 554 | ||
562 | /* Schedule reprobing of all unregistered subchannels. */ | 555 | /* Schedule reprobing of all unregistered subchannels. */ |
563 | void css_schedule_reprobe(void) | 556 | void css_schedule_reprobe(void) |
564 | { | 557 | { |
565 | need_reprobe = 1; | 558 | css_schedule_eval_all_unreg(); |
566 | queue_work(slow_path_wq, &css_reprobe_work); | ||
567 | } | 559 | } |
568 | |||
569 | EXPORT_SYMBOL_GPL(css_schedule_reprobe); | 560 | EXPORT_SYMBOL_GPL(css_schedule_reprobe); |
570 | 561 | ||
571 | /* | 562 | /* |
@@ -601,49 +592,6 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) | |||
601 | css_evaluate_subchannel(mchk_schid, 0); | 592 | css_evaluate_subchannel(mchk_schid, 0); |
602 | } | 593 | } |
603 | 594 | ||
604 | static int __init | ||
605 | __init_channel_subsystem(struct subchannel_id schid, void *data) | ||
606 | { | ||
607 | struct subchannel *sch; | ||
608 | int ret; | ||
609 | |||
610 | if (cio_is_console(schid)) | ||
611 | sch = cio_get_console_subchannel(); | ||
612 | else { | ||
613 | sch = css_alloc_subchannel(schid); | ||
614 | if (IS_ERR(sch)) | ||
615 | ret = PTR_ERR(sch); | ||
616 | else | ||
617 | ret = 0; | ||
618 | switch (ret) { | ||
619 | case 0: | ||
620 | break; | ||
621 | case -ENOMEM: | ||
622 | panic("Out of memory in init_channel_subsystem\n"); | ||
623 | /* -ENXIO: no more subchannels. */ | ||
624 | case -ENXIO: | ||
625 | return ret; | ||
626 | /* -EIO: this subchannel set not supported. */ | ||
627 | case -EIO: | ||
628 | return ret; | ||
629 | default: | ||
630 | return 0; | ||
631 | } | ||
632 | } | ||
633 | /* | ||
634 | * We register ALL valid subchannels in ioinfo, even those | ||
635 | * that have been present before init_channel_subsystem. | ||
636 | * These subchannels can't have been registered yet (kmalloc | ||
637 | * not working) so we do it now. This is true e.g. for the | ||
638 | * console subchannel. | ||
639 | */ | ||
640 | if (css_register_subchannel(sch)) { | ||
641 | if (!cio_is_console(schid)) | ||
642 | put_device(&sch->dev); | ||
643 | } | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static void __init | 595 | static void __init |
648 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) | 596 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) |
649 | { | 597 | { |
@@ -854,19 +802,30 @@ static struct notifier_block css_power_notifier = { | |||
854 | * The struct subchannel's are created during probing (except for the | 802 | * The struct subchannel's are created during probing (except for the |
855 | * static console subchannel). | 803 | * static console subchannel). |
856 | */ | 804 | */ |
857 | static int __init | 805 | static int __init css_bus_init(void) |
858 | init_channel_subsystem (void) | ||
859 | { | 806 | { |
860 | int ret, i; | 807 | int ret, i; |
861 | 808 | ||
862 | ret = chsc_determine_css_characteristics(); | 809 | ret = chsc_determine_css_characteristics(); |
863 | if (ret == -ENOMEM) | 810 | if (ret == -ENOMEM) |
864 | goto out; /* No need to continue. */ | 811 | goto out; |
865 | 812 | ||
866 | ret = chsc_alloc_sei_area(); | 813 | ret = chsc_alloc_sei_area(); |
867 | if (ret) | 814 | if (ret) |
868 | goto out; | 815 | goto out; |
869 | 816 | ||
817 | /* Try to enable MSS. */ | ||
818 | ret = chsc_enable_facility(CHSC_SDA_OC_MSS); | ||
819 | switch (ret) { | ||
820 | case 0: /* Success. */ | ||
821 | max_ssid = __MAX_SSID; | ||
822 | break; | ||
823 | case -ENOMEM: | ||
824 | goto out; | ||
825 | default: | ||
826 | max_ssid = 0; | ||
827 | } | ||
828 | |||
870 | ret = slow_subchannel_init(); | 829 | ret = slow_subchannel_init(); |
871 | if (ret) | 830 | if (ret) |
872 | goto out; | 831 | goto out; |
@@ -878,17 +837,6 @@ init_channel_subsystem (void) | |||
878 | if ((ret = bus_register(&css_bus_type))) | 837 | if ((ret = bus_register(&css_bus_type))) |
879 | goto out; | 838 | goto out; |
880 | 839 | ||
881 | /* Try to enable MSS. */ | ||
882 | ret = chsc_enable_facility(CHSC_SDA_OC_MSS); | ||
883 | switch (ret) { | ||
884 | case 0: /* Success. */ | ||
885 | max_ssid = __MAX_SSID; | ||
886 | break; | ||
887 | case -ENOMEM: | ||
888 | goto out_bus; | ||
889 | default: | ||
890 | max_ssid = 0; | ||
891 | } | ||
892 | /* Setup css structure. */ | 840 | /* Setup css structure. */ |
893 | for (i = 0; i <= __MAX_CSSID; i++) { | 841 | for (i = 0; i <= __MAX_CSSID; i++) { |
894 | struct channel_subsystem *css; | 842 | struct channel_subsystem *css; |
@@ -934,7 +882,6 @@ init_channel_subsystem (void) | |||
934 | /* Enable default isc for I/O subchannels. */ | 882 | /* Enable default isc for I/O subchannels. */ |
935 | isc_register(IO_SCH_ISC); | 883 | isc_register(IO_SCH_ISC); |
936 | 884 | ||
937 | for_each_subchannel(__init_channel_subsystem, NULL); | ||
938 | return 0; | 885 | return 0; |
939 | out_file: | 886 | out_file: |
940 | if (css_chsc_characteristics.secm) | 887 | if (css_chsc_characteristics.secm) |
@@ -955,17 +902,76 @@ out_unregister: | |||
955 | &dev_attr_cm_enable); | 902 | &dev_attr_cm_enable); |
956 | device_unregister(&css->device); | 903 | device_unregister(&css->device); |
957 | } | 904 | } |
958 | out_bus: | ||
959 | bus_unregister(&css_bus_type); | 905 | bus_unregister(&css_bus_type); |
960 | out: | 906 | out: |
961 | crw_unregister_handler(CRW_RSC_CSS); | 907 | crw_unregister_handler(CRW_RSC_CSS); |
962 | chsc_free_sei_area(); | 908 | chsc_free_sei_area(); |
963 | kfree(slow_subchannel_set); | 909 | idset_free(slow_subchannel_set); |
964 | pr_alert("The CSS device driver initialization failed with " | 910 | pr_alert("The CSS device driver initialization failed with " |
965 | "errno=%d\n", ret); | 911 | "errno=%d\n", ret); |
966 | return ret; | 912 | return ret; |
967 | } | 913 | } |
968 | 914 | ||
915 | static void __init css_bus_cleanup(void) | ||
916 | { | ||
917 | struct channel_subsystem *css; | ||
918 | int i; | ||
919 | |||
920 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
921 | css = channel_subsystems[i]; | ||
922 | device_unregister(&css->pseudo_subchannel->dev); | ||
923 | css->pseudo_subchannel = NULL; | ||
924 | if (css_chsc_characteristics.secm) | ||
925 | device_remove_file(&css->device, &dev_attr_cm_enable); | ||
926 | device_unregister(&css->device); | ||
927 | } | ||
928 | bus_unregister(&css_bus_type); | ||
929 | crw_unregister_handler(CRW_RSC_CSS); | ||
930 | chsc_free_sei_area(); | ||
931 | idset_free(slow_subchannel_set); | ||
932 | isc_unregister(IO_SCH_ISC); | ||
933 | } | ||
934 | |||
935 | static int __init channel_subsystem_init(void) | ||
936 | { | ||
937 | int ret; | ||
938 | |||
939 | ret = css_bus_init(); | ||
940 | if (ret) | ||
941 | return ret; | ||
942 | |||
943 | ret = io_subchannel_init(); | ||
944 | if (ret) | ||
945 | css_bus_cleanup(); | ||
946 | |||
947 | return ret; | ||
948 | } | ||
949 | subsys_initcall(channel_subsystem_init); | ||
950 | |||
951 | static int css_settle(struct device_driver *drv, void *unused) | ||
952 | { | ||
953 | struct css_driver *cssdrv = to_cssdriver(drv); | ||
954 | |||
955 | if (cssdrv->settle) | ||
956 | cssdrv->settle(); | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | /* | ||
961 | * Wait for the initialization of devices to finish, to make sure we are | ||
962 | * done with our setup if the search for the root device starts. | ||
963 | */ | ||
964 | static int __init channel_subsystem_init_sync(void) | ||
965 | { | ||
966 | /* Start initial subchannel evaluation. */ | ||
967 | css_schedule_eval_all(); | ||
968 | /* Wait for the evaluation of subchannels to finish. */ | ||
969 | wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); | ||
970 | /* Wait for the subchannel type specific initialization to finish */ | ||
971 | return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle); | ||
972 | } | ||
973 | subsys_initcall_sync(channel_subsystem_init_sync); | ||
974 | |||
969 | int sch_is_pseudo_sch(struct subchannel *sch) | 975 | int sch_is_pseudo_sch(struct subchannel *sch) |
970 | { | 976 | { |
971 | return sch == to_css(sch->dev.parent)->pseudo_subchannel; | 977 | return sch == to_css(sch->dev.parent)->pseudo_subchannel; |
@@ -1135,7 +1141,5 @@ void css_driver_unregister(struct css_driver *cdrv) | |||
1135 | } | 1141 | } |
1136 | EXPORT_SYMBOL_GPL(css_driver_unregister); | 1142 | EXPORT_SYMBOL_GPL(css_driver_unregister); |
1137 | 1143 | ||
1138 | subsys_initcall(init_channel_subsystem); | ||
1139 | |||
1140 | MODULE_LICENSE("GPL"); | 1144 | MODULE_LICENSE("GPL"); |
1141 | EXPORT_SYMBOL(css_bus_type); | 1145 | EXPORT_SYMBOL(css_bus_type); |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 9763eeec7458..68d6b0bf151c 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -75,6 +75,7 @@ struct chp_link; | |||
75 | * @freeze: callback for freezing during hibernation snapshotting | 75 | * @freeze: callback for freezing during hibernation snapshotting |
76 | * @thaw: undo work done in @freeze | 76 | * @thaw: undo work done in @freeze |
77 | * @restore: callback for restoring after hibernation | 77 | * @restore: callback for restoring after hibernation |
78 | * @settle: wait for asynchronous work to finish | ||
78 | * @name: name of the device driver | 79 | * @name: name of the device driver |
79 | */ | 80 | */ |
80 | struct css_driver { | 81 | struct css_driver { |
@@ -92,6 +93,7 @@ struct css_driver { | |||
92 | int (*freeze)(struct subchannel *); | 93 | int (*freeze)(struct subchannel *); |
93 | int (*thaw) (struct subchannel *); | 94 | int (*thaw) (struct subchannel *); |
94 | int (*restore)(struct subchannel *); | 95 | int (*restore)(struct subchannel *); |
96 | void (*settle)(void); | ||
95 | const char *name; | 97 | const char *name; |
96 | }; | 98 | }; |
97 | 99 | ||
@@ -109,6 +111,7 @@ extern void css_sch_device_unregister(struct subchannel *); | |||
109 | extern int css_probe_device(struct subchannel_id); | 111 | extern int css_probe_device(struct subchannel_id); |
110 | extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); | 112 | extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); |
111 | extern int css_init_done; | 113 | extern int css_init_done; |
114 | extern int max_ssid; | ||
112 | int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), | 115 | int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), |
113 | int (*fn_unknown)(struct subchannel_id, | 116 | int (*fn_unknown)(struct subchannel_id, |
114 | void *), void *data); | 117 | void *), void *data); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6527f3f34493..f780bdd3a04e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -131,6 +131,10 @@ static void io_subchannel_shutdown(struct subchannel *); | |||
131 | static int io_subchannel_sch_event(struct subchannel *, int); | 131 | static int io_subchannel_sch_event(struct subchannel *, int); |
132 | static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, | 132 | static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, |
133 | int); | 133 | int); |
134 | static void recovery_func(unsigned long data); | ||
135 | struct workqueue_struct *ccw_device_work; | ||
136 | wait_queue_head_t ccw_device_init_wq; | ||
137 | atomic_t ccw_device_init_count; | ||
134 | 138 | ||
135 | static struct css_device_id io_subchannel_ids[] = { | 139 | static struct css_device_id io_subchannel_ids[] = { |
136 | { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, | 140 | { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, |
@@ -151,6 +155,13 @@ static int io_subchannel_prepare(struct subchannel *sch) | |||
151 | return 0; | 155 | return 0; |
152 | } | 156 | } |
153 | 157 | ||
158 | static void io_subchannel_settle(void) | ||
159 | { | ||
160 | wait_event(ccw_device_init_wq, | ||
161 | atomic_read(&ccw_device_init_count) == 0); | ||
162 | flush_workqueue(ccw_device_work); | ||
163 | } | ||
164 | |||
154 | static struct css_driver io_subchannel_driver = { | 165 | static struct css_driver io_subchannel_driver = { |
155 | .owner = THIS_MODULE, | 166 | .owner = THIS_MODULE, |
156 | .subchannel_type = io_subchannel_ids, | 167 | .subchannel_type = io_subchannel_ids, |
@@ -162,16 +173,10 @@ static struct css_driver io_subchannel_driver = { | |||
162 | .remove = io_subchannel_remove, | 173 | .remove = io_subchannel_remove, |
163 | .shutdown = io_subchannel_shutdown, | 174 | .shutdown = io_subchannel_shutdown, |
164 | .prepare = io_subchannel_prepare, | 175 | .prepare = io_subchannel_prepare, |
176 | .settle = io_subchannel_settle, | ||
165 | }; | 177 | }; |
166 | 178 | ||
167 | struct workqueue_struct *ccw_device_work; | 179 | int __init io_subchannel_init(void) |
168 | wait_queue_head_t ccw_device_init_wq; | ||
169 | atomic_t ccw_device_init_count; | ||
170 | |||
171 | static void recovery_func(unsigned long data); | ||
172 | |||
173 | static int __init | ||
174 | init_ccw_bus_type (void) | ||
175 | { | 180 | { |
176 | int ret; | 181 | int ret; |
177 | 182 | ||
@@ -181,10 +186,10 @@ init_ccw_bus_type (void) | |||
181 | 186 | ||
182 | ccw_device_work = create_singlethread_workqueue("cio"); | 187 | ccw_device_work = create_singlethread_workqueue("cio"); |
183 | if (!ccw_device_work) | 188 | if (!ccw_device_work) |
184 | return -ENOMEM; /* FIXME: better errno ? */ | 189 | return -ENOMEM; |
185 | slow_path_wq = create_singlethread_workqueue("kslowcrw"); | 190 | slow_path_wq = create_singlethread_workqueue("kslowcrw"); |
186 | if (!slow_path_wq) { | 191 | if (!slow_path_wq) { |
187 | ret = -ENOMEM; /* FIXME: better errno ? */ | 192 | ret = -ENOMEM; |
188 | goto out_err; | 193 | goto out_err; |
189 | } | 194 | } |
190 | if ((ret = bus_register (&ccw_bus_type))) | 195 | if ((ret = bus_register (&ccw_bus_type))) |
@@ -194,9 +199,6 @@ init_ccw_bus_type (void) | |||
194 | if (ret) | 199 | if (ret) |
195 | goto out_err; | 200 | goto out_err; |
196 | 201 | ||
197 | wait_event(ccw_device_init_wq, | ||
198 | atomic_read(&ccw_device_init_count) == 0); | ||
199 | flush_workqueue(ccw_device_work); | ||
200 | return 0; | 202 | return 0; |
201 | out_err: | 203 | out_err: |
202 | if (ccw_device_work) | 204 | if (ccw_device_work) |
@@ -206,16 +208,6 @@ out_err: | |||
206 | return ret; | 208 | return ret; |
207 | } | 209 | } |
208 | 210 | ||
209 | static void __exit | ||
210 | cleanup_ccw_bus_type (void) | ||
211 | { | ||
212 | css_driver_unregister(&io_subchannel_driver); | ||
213 | bus_unregister(&ccw_bus_type); | ||
214 | destroy_workqueue(ccw_device_work); | ||
215 | } | ||
216 | |||
217 | subsys_initcall(init_ccw_bus_type); | ||
218 | module_exit(cleanup_ccw_bus_type); | ||
219 | 211 | ||
220 | /************************ device handling **************************/ | 212 | /************************ device handling **************************/ |
221 | 213 | ||
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index e3975107a578..ed39a2caaf47 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -74,6 +74,7 @@ dev_fsm_final_state(struct ccw_device *cdev) | |||
74 | extern struct workqueue_struct *ccw_device_work; | 74 | extern struct workqueue_struct *ccw_device_work; |
75 | extern wait_queue_head_t ccw_device_init_wq; | 75 | extern wait_queue_head_t ccw_device_init_wq; |
76 | extern atomic_t ccw_device_init_count; | 76 | extern atomic_t ccw_device_init_count; |
77 | int __init io_subchannel_init(void); | ||
77 | 78 | ||
78 | void io_subchannel_recog_done(struct ccw_device *cdev); | 79 | void io_subchannel_recog_done(struct ccw_device *cdev); |
79 | void io_subchannel_init_config(struct subchannel *sch); | 80 | void io_subchannel_init_config(struct subchannel *sch); |
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index cf8f24a4b5eb..4d10981c7cc1 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c | |||
@@ -78,7 +78,7 @@ static inline int idset_get_first(struct idset *set, int *ssid, int *id) | |||
78 | 78 | ||
79 | struct idset *idset_sch_new(void) | 79 | struct idset *idset_sch_new(void) |
80 | { | 80 | { |
81 | return idset_new(__MAX_SSID + 1, __MAX_SUBCHANNEL + 1); | 81 | return idset_new(max_ssid + 1, __MAX_SUBCHANNEL + 1); |
82 | } | 82 | } |
83 | 83 | ||
84 | void idset_sch_add(struct idset *set, struct subchannel_id schid) | 84 | void idset_sch_add(struct idset *set, struct subchannel_id schid) |
@@ -110,3 +110,23 @@ int idset_sch_get_first(struct idset *set, struct subchannel_id *schid) | |||
110 | } | 110 | } |
111 | return rc; | 111 | return rc; |
112 | } | 112 | } |
113 | |||
114 | int idset_is_empty(struct idset *set) | ||
115 | { | ||
116 | int bitnum; | ||
117 | |||
118 | bitnum = find_first_bit(set->bitmap, set->num_ssid * set->num_id); | ||
119 | if (bitnum >= set->num_ssid * set->num_id) | ||
120 | return 1; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | void idset_add_set(struct idset *to, struct idset *from) | ||
125 | { | ||
126 | unsigned long i, len; | ||
127 | |||
128 | len = min(__BITOPS_WORDS(to->num_ssid * to->num_id), | ||
129 | __BITOPS_WORDS(from->num_ssid * from->num_id)); | ||
130 | for (i = 0; i < len ; i++) | ||
131 | to->bitmap[i] |= from->bitmap[i]; | ||
132 | } | ||
diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 528065cb5021..7543da4529f9 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h | |||
@@ -21,5 +21,7 @@ void idset_sch_add(struct idset *set, struct subchannel_id id); | |||
21 | void idset_sch_del(struct idset *set, struct subchannel_id id); | 21 | void idset_sch_del(struct idset *set, struct subchannel_id id); |
22 | int idset_sch_contains(struct idset *set, struct subchannel_id id); | 22 | int idset_sch_contains(struct idset *set, struct subchannel_id id); |
23 | int idset_sch_get_first(struct idset *set, struct subchannel_id *id); | 23 | int idset_sch_get_first(struct idset *set, struct subchannel_id *id); |
24 | int idset_is_empty(struct idset *set); | ||
25 | void idset_add_set(struct idset *to, struct idset *from); | ||
24 | 26 | ||
25 | #endif /* S390_IDSET_H */ | 27 | #endif /* S390_IDSET_H */ |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 9aef402a5f1b..4be6e84b9599 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -401,7 +401,7 @@ static void announce_buffer_error(struct qdio_q *q, int count) | |||
401 | if ((!q->is_input_q && | 401 | if ((!q->is_input_q && |
402 | (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { | 402 | (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { |
403 | qdio_perf_stat_inc(&perf_stats.outbound_target_full); | 403 | qdio_perf_stat_inc(&perf_stats.outbound_target_full); |
404 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d", | 404 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x", |
405 | q->first_to_check); | 405 | q->first_to_check); |
406 | return; | 406 | return; |
407 | } | 407 | } |
@@ -418,7 +418,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
418 | { | 418 | { |
419 | int new; | 419 | int new; |
420 | 420 | ||
421 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); | 421 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %02x", count); |
422 | 422 | ||
423 | /* for QEBSM the ACK was already set by EQBS */ | 423 | /* for QEBSM the ACK was already set by EQBS */ |
424 | if (is_qebsm(q)) { | 424 | if (is_qebsm(q)) { |
@@ -455,6 +455,8 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
455 | count--; | 455 | count--; |
456 | if (!count) | 456 | if (!count) |
457 | return; | 457 | return; |
458 | /* need to change ALL buffers to get more interrupts */ | ||
459 | set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, count); | ||
458 | } | 460 | } |
459 | 461 | ||
460 | static int get_inbound_buffer_frontier(struct qdio_q *q) | 462 | static int get_inbound_buffer_frontier(struct qdio_q *q) |
@@ -545,7 +547,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) | |||
545 | * has (probably) not moved (see qdio_inbound_processing). | 547 | * has (probably) not moved (see qdio_inbound_processing). |
546 | */ | 548 | */ |
547 | if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { | 549 | if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { |
548 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", | 550 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", |
549 | q->first_to_check); | 551 | q->first_to_check); |
550 | return 1; | 552 | return 1; |
551 | } else | 553 | } else |
@@ -565,11 +567,10 @@ static void qdio_kick_handler(struct qdio_q *q) | |||
565 | 567 | ||
566 | if (q->is_input_q) { | 568 | if (q->is_input_q) { |
567 | qdio_perf_stat_inc(&perf_stats.inbound_handler); | 569 | qdio_perf_stat_inc(&perf_stats.inbound_handler); |
568 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); | 570 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); |
569 | } else { | 571 | } else |
570 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr); | 572 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", |
571 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); | 573 | start, count); |
572 | } | ||
573 | 574 | ||
574 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, | 575 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, |
575 | q->irq_ptr->int_parm); | 576 | q->irq_ptr->int_parm); |
@@ -633,7 +634,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) | |||
633 | switch (state) { | 634 | switch (state) { |
634 | case SLSB_P_OUTPUT_EMPTY: | 635 | case SLSB_P_OUTPUT_EMPTY: |
635 | /* the adapter got it */ | 636 | /* the adapter got it */ |
636 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count); | 637 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %02x", q->nr, count); |
637 | 638 | ||
638 | atomic_sub(count, &q->nr_buf_used); | 639 | atomic_sub(count, &q->nr_buf_used); |
639 | q->first_to_check = add_buf(q->first_to_check, count); | 640 | q->first_to_check = add_buf(q->first_to_check, count); |
@@ -1481,10 +1482,9 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, | |||
1481 | get_buf_state(q, prev_buf(bufnr), &state, 0); | 1482 | get_buf_state(q, prev_buf(bufnr), &state, 0); |
1482 | if (state != SLSB_CU_OUTPUT_PRIMED) | 1483 | if (state != SLSB_CU_OUTPUT_PRIMED) |
1483 | rc = qdio_kick_outbound_q(q); | 1484 | rc = qdio_kick_outbound_q(q); |
1484 | else { | 1485 | else |
1485 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); | ||
1486 | qdio_perf_stat_inc(&perf_stats.fast_requeue); | 1486 | qdio_perf_stat_inc(&perf_stats.fast_requeue); |
1487 | } | 1487 | |
1488 | out: | 1488 | out: |
1489 | tasklet_schedule(&q->tasklet); | 1489 | tasklet_schedule(&q->tasklet); |
1490 | return rc; | 1490 | return rc; |
@@ -1510,12 +1510,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1510 | if (!irq_ptr) | 1510 | if (!irq_ptr) |
1511 | return -ENODEV; | 1511 | return -ENODEV; |
1512 | 1512 | ||
1513 | if (callflags & QDIO_FLAG_SYNC_INPUT) | 1513 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, |
1514 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input"); | 1514 | "do%02x b:%02x c:%02x", callflags, bufnr, count); |
1515 | else | ||
1516 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output"); | ||
1517 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags); | ||
1518 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count); | ||
1519 | 1515 | ||
1520 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) | 1516 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) |
1521 | return -EBUSY; | 1517 | return -EBUSY; |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 090b32a339c6..1294876bf7b4 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -60,6 +60,7 @@ static int ap_device_probe(struct device *dev); | |||
60 | static void ap_interrupt_handler(void *unused1, void *unused2); | 60 | static void ap_interrupt_handler(void *unused1, void *unused2); |
61 | static void ap_reset(struct ap_device *ap_dev); | 61 | static void ap_reset(struct ap_device *ap_dev); |
62 | static void ap_config_timeout(unsigned long ptr); | 62 | static void ap_config_timeout(unsigned long ptr); |
63 | static int ap_select_domain(void); | ||
63 | 64 | ||
64 | /* | 65 | /* |
65 | * Module description. | 66 | * Module description. |
@@ -109,6 +110,10 @@ static unsigned long long poll_timeout = 250000; | |||
109 | 110 | ||
110 | /* Suspend flag */ | 111 | /* Suspend flag */ |
111 | static int ap_suspend_flag; | 112 | static int ap_suspend_flag; |
113 | /* Flag to check if domain was set through module parameter domain=. This is | ||
114 | * important when supsend and resume is done in a z/VM environment where the | ||
115 | * domain might change. */ | ||
116 | static int user_set_domain = 0; | ||
112 | static struct bus_type ap_bus_type; | 117 | static struct bus_type ap_bus_type; |
113 | 118 | ||
114 | /** | 119 | /** |
@@ -643,6 +648,7 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
643 | destroy_workqueue(ap_work_queue); | 648 | destroy_workqueue(ap_work_queue); |
644 | ap_work_queue = NULL; | 649 | ap_work_queue = NULL; |
645 | } | 650 | } |
651 | |||
646 | tasklet_disable(&ap_tasklet); | 652 | tasklet_disable(&ap_tasklet); |
647 | } | 653 | } |
648 | /* Poll on the device until all requests are finished. */ | 654 | /* Poll on the device until all requests are finished. */ |
@@ -653,7 +659,10 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
653 | spin_unlock_bh(&ap_dev->lock); | 659 | spin_unlock_bh(&ap_dev->lock); |
654 | } while ((flags & 1) || (flags & 2)); | 660 | } while ((flags & 1) || (flags & 2)); |
655 | 661 | ||
656 | ap_device_remove(dev); | 662 | spin_lock_bh(&ap_dev->lock); |
663 | ap_dev->unregistered = 1; | ||
664 | spin_unlock_bh(&ap_dev->lock); | ||
665 | |||
657 | return 0; | 666 | return 0; |
658 | } | 667 | } |
659 | 668 | ||
@@ -666,11 +675,10 @@ static int ap_bus_resume(struct device *dev) | |||
666 | ap_suspend_flag = 0; | 675 | ap_suspend_flag = 0; |
667 | if (!ap_interrupts_available()) | 676 | if (!ap_interrupts_available()) |
668 | ap_interrupt_indicator = NULL; | 677 | ap_interrupt_indicator = NULL; |
669 | ap_device_probe(dev); | 678 | if (!user_set_domain) { |
670 | ap_reset(ap_dev); | 679 | ap_domain_index = -1; |
671 | setup_timer(&ap_dev->timeout, ap_request_timeout, | 680 | ap_select_domain(); |
672 | (unsigned long) ap_dev); | 681 | } |
673 | ap_scan_bus(NULL); | ||
674 | init_timer(&ap_config_timer); | 682 | init_timer(&ap_config_timer); |
675 | ap_config_timer.function = ap_config_timeout; | 683 | ap_config_timer.function = ap_config_timeout; |
676 | ap_config_timer.data = 0; | 684 | ap_config_timer.data = 0; |
@@ -686,12 +694,14 @@ static int ap_bus_resume(struct device *dev) | |||
686 | tasklet_schedule(&ap_tasklet); | 694 | tasklet_schedule(&ap_tasklet); |
687 | if (ap_thread_flag) | 695 | if (ap_thread_flag) |
688 | rc = ap_poll_thread_start(); | 696 | rc = ap_poll_thread_start(); |
689 | } else { | ||
690 | ap_device_probe(dev); | ||
691 | ap_reset(ap_dev); | ||
692 | setup_timer(&ap_dev->timeout, ap_request_timeout, | ||
693 | (unsigned long) ap_dev); | ||
694 | } | 697 | } |
698 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { | ||
699 | spin_lock_bh(&ap_dev->lock); | ||
700 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), | ||
701 | ap_domain_index); | ||
702 | spin_unlock_bh(&ap_dev->lock); | ||
703 | } | ||
704 | queue_work(ap_work_queue, &ap_config_work); | ||
695 | 705 | ||
696 | return rc; | 706 | return rc; |
697 | } | 707 | } |
@@ -1079,6 +1089,8 @@ static void ap_scan_bus(struct work_struct *unused) | |||
1079 | spin_lock_bh(&ap_dev->lock); | 1089 | spin_lock_bh(&ap_dev->lock); |
1080 | if (rc || ap_dev->unregistered) { | 1090 | if (rc || ap_dev->unregistered) { |
1081 | spin_unlock_bh(&ap_dev->lock); | 1091 | spin_unlock_bh(&ap_dev->lock); |
1092 | if (ap_dev->unregistered) | ||
1093 | i--; | ||
1082 | device_unregister(dev); | 1094 | device_unregister(dev); |
1083 | put_device(dev); | 1095 | put_device(dev); |
1084 | continue; | 1096 | continue; |
@@ -1586,6 +1598,12 @@ int __init ap_module_init(void) | |||
1586 | ap_domain_index); | 1598 | ap_domain_index); |
1587 | return -EINVAL; | 1599 | return -EINVAL; |
1588 | } | 1600 | } |
1601 | /* In resume callback we need to know if the user had set the domain. | ||
1602 | * If so, we can not just reset it. | ||
1603 | */ | ||
1604 | if (ap_domain_index >= 0) | ||
1605 | user_set_domain = 1; | ||
1606 | |||
1589 | if (ap_instructions_available() != 0) { | 1607 | if (ap_instructions_available() != 0) { |
1590 | pr_warning("The hardware system does not support " | 1608 | pr_warning("The hardware system does not support " |
1591 | "AP instructions\n"); | 1609 | "AP instructions\n"); |