diff options
-rw-r--r-- | Documentation/DocBook/s390-drivers.tmpl | 21 | ||||
-rw-r--r-- | arch/s390/Kconfig | 8 | ||||
-rw-r--r-- | arch/s390/Kconfig.debug | 8 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 7 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 7 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 27 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 14 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 13 | ||||
-rw-r--r-- | arch/s390/kernel/stacktrace.c | 31 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 5 | ||||
-rw-r--r-- | arch/s390/kernel/vmlinux.lds.S | 2 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 27 | ||||
-rw-r--r-- | arch/s390/mm/vmem.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/dasd.c | 19 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 62 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 5 | ||||
-rw-r--r-- | drivers/s390/char/sclp_tty.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 147 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 107 | ||||
-rw-r--r-- | include/asm-s390/bitops.h | 558 | ||||
-rw-r--r-- | include/asm-s390/cacheflush.h | 4 | ||||
-rw-r--r-- | include/asm-s390/ccwgroup.h | 2 | ||||
-rw-r--r-- | include/asm-s390/pgtable.h | 12 |
25 files changed, 587 insertions, 520 deletions
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl index 3d2f31b99dd9..4acc73240a6d 100644 --- a/Documentation/DocBook/s390-drivers.tmpl +++ b/Documentation/DocBook/s390-drivers.tmpl | |||
@@ -59,7 +59,7 @@ | |||
59 | <title>Introduction</title> | 59 | <title>Introduction</title> |
60 | <para> | 60 | <para> |
61 | This document describes the interfaces available for device drivers that | 61 | This document describes the interfaces available for device drivers that |
62 | drive s390 based channel attached devices. This includes interfaces for | 62 | drive s390 based channel attached I/O devices. This includes interfaces for |
63 | interaction with the hardware and interfaces for interacting with the | 63 | interaction with the hardware and interfaces for interacting with the |
64 | common driver core. Those interfaces are provided by the s390 common I/O | 64 | common driver core. Those interfaces are provided by the s390 common I/O |
65 | layer. | 65 | layer. |
@@ -86,9 +86,10 @@ | |||
86 | The ccw bus typically contains the majority of devices available to | 86 | The ccw bus typically contains the majority of devices available to |
87 | a s390 system. Named after the channel command word (ccw), the basic | 87 | a s390 system. Named after the channel command word (ccw), the basic |
88 | command structure used to address its devices, the ccw bus contains | 88 | command structure used to address its devices, the ccw bus contains |
89 | so-called channel attached devices. They are addressed via subchannels, | 89 | so-called channel attached devices. They are addressed via I/O |
90 | visible on the css bus. A device driver, however, will never interact | 90 | subchannels, visible on the css bus. A device driver for |
91 | with the subchannel directly, but only via the device on the ccw bus, | 91 | channel-attached devices, however, will never interact with the |
92 | subchannel directly, but only via the I/O device on the ccw bus, | ||
92 | the ccw device. | 93 | the ccw device. |
93 | </para> | 94 | </para> |
94 | <sect1 id="channelIO"> | 95 | <sect1 id="channelIO"> |
@@ -116,7 +117,6 @@ | |||
116 | !Iinclude/asm-s390/ccwdev.h | 117 | !Iinclude/asm-s390/ccwdev.h |
117 | !Edrivers/s390/cio/device.c | 118 | !Edrivers/s390/cio/device.c |
118 | !Edrivers/s390/cio/device_ops.c | 119 | !Edrivers/s390/cio/device_ops.c |
119 | !Edrivers/s390/cio/airq.c | ||
120 | </sect1> | 120 | </sect1> |
121 | <sect1 id="cmf"> | 121 | <sect1 id="cmf"> |
122 | <title>The channel-measurement facility</title> | 122 | <title>The channel-measurement facility</title> |
@@ -147,4 +147,15 @@ | |||
147 | </sect1> | 147 | </sect1> |
148 | </chapter> | 148 | </chapter> |
149 | 149 | ||
150 | <chapter id="genericinterfaces"> | ||
151 | <title>Generic interfaces</title> | ||
152 | <para> | ||
153 | Some interfaces are available to other drivers that do not necessarily | ||
154 | have anything to do with the busses described above, but still are | ||
155 | indirectly using basic infrastructure in the common I/O layer. | ||
156 | One example is the support for adapter interrupts. | ||
157 | </para> | ||
158 | !Edrivers/s390/cio/airq.c | ||
159 | </chapter> | ||
160 | |||
150 | </book> | 161 | </book> |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 82cbffd03654..92a4f7b4323a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -16,6 +16,9 @@ config LOCKDEP_SUPPORT | |||
16 | config STACKTRACE_SUPPORT | 16 | config STACKTRACE_SUPPORT |
17 | def_bool y | 17 | def_bool y |
18 | 18 | ||
19 | config HAVE_LATENCYTOP_SUPPORT | ||
20 | def_bool y | ||
21 | |||
19 | config RWSEM_GENERIC_SPINLOCK | 22 | config RWSEM_GENERIC_SPINLOCK |
20 | bool | 23 | bool |
21 | 24 | ||
@@ -47,6 +50,11 @@ config NO_IOMEM | |||
47 | config NO_DMA | 50 | config NO_DMA |
48 | def_bool y | 51 | def_bool y |
49 | 52 | ||
53 | config GENERIC_LOCKBREAK | ||
54 | bool | ||
55 | default y | ||
56 | depends on SMP && PREEMPT | ||
57 | |||
50 | mainmenu "Linux Kernel Configuration" | 58 | mainmenu "Linux Kernel Configuration" |
51 | 59 | ||
52 | config S390 | 60 | config S390 |
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 2283933a9a93..4599fa06bd82 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug | |||
@@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT | |||
6 | 6 | ||
7 | source "lib/Kconfig.debug" | 7 | source "lib/Kconfig.debug" |
8 | 8 | ||
9 | config DEBUG_PAGEALLOC | ||
10 | bool "Debug page memory allocations" | ||
11 | depends on DEBUG_KERNEL | ||
12 | help | ||
13 | Unmap pages from the kernel linear mapping after free_pages(). | ||
14 | This results in a slowdown, but helps to find certain types of | ||
15 | memory corruptions. | ||
16 | |||
9 | endmenu | 17 | endmenu |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1a6dac8df6fb..6766e37fe8ea 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/sys.h> | 12 | #include <linux/sys.h> |
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <linux/init.h> | ||
14 | #include <asm/cache.h> | 15 | #include <asm/cache.h> |
15 | #include <asm/lowcore.h> | 16 | #include <asm/lowcore.h> |
16 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
@@ -830,9 +831,7 @@ mcck_return: | |||
830 | * Restart interruption handler, kick starter for additional CPUs | 831 | * Restart interruption handler, kick starter for additional CPUs |
831 | */ | 832 | */ |
832 | #ifdef CONFIG_SMP | 833 | #ifdef CONFIG_SMP |
833 | #ifndef CONFIG_HOTPLUG_CPU | 834 | __CPUINIT |
834 | .section .init.text,"ax" | ||
835 | #endif | ||
836 | .globl restart_int_handler | 835 | .globl restart_int_handler |
837 | restart_int_handler: | 836 | restart_int_handler: |
838 | l %r15,__LC_SAVE_AREA+60 # load ksp | 837 | l %r15,__LC_SAVE_AREA+60 # load ksp |
@@ -845,9 +844,7 @@ restart_int_handler: | |||
845 | br %r14 # branch to start_secondary | 844 | br %r14 # branch to start_secondary |
846 | restart_addr: | 845 | restart_addr: |
847 | .long start_secondary | 846 | .long start_secondary |
848 | #ifndef CONFIG_HOTPLUG_CPU | ||
849 | .previous | 847 | .previous |
850 | #endif | ||
851 | #else | 848 | #else |
852 | /* | 849 | /* |
853 | * If we do not run with SMP enabled, let the new CPU crash ... | 850 | * If we do not run with SMP enabled, let the new CPU crash ... |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index a3e47b893f07..efde6e178f6c 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/sys.h> | 12 | #include <linux/sys.h> |
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <linux/init.h> | ||
14 | #include <asm/cache.h> | 15 | #include <asm/cache.h> |
15 | #include <asm/lowcore.h> | 16 | #include <asm/lowcore.h> |
16 | #include <asm/errno.h> | 17 | #include <asm/errno.h> |
@@ -801,9 +802,7 @@ mcck_return: | |||
801 | * Restart interruption handler, kick starter for additional CPUs | 802 | * Restart interruption handler, kick starter for additional CPUs |
802 | */ | 803 | */ |
803 | #ifdef CONFIG_SMP | 804 | #ifdef CONFIG_SMP |
804 | #ifndef CONFIG_HOTPLUG_CPU | 805 | __CPUINIT |
805 | .section .init.text,"ax" | ||
806 | #endif | ||
807 | .globl restart_int_handler | 806 | .globl restart_int_handler |
808 | restart_int_handler: | 807 | restart_int_handler: |
809 | lg %r15,__LC_SAVE_AREA+120 # load ksp | 808 | lg %r15,__LC_SAVE_AREA+120 # load ksp |
@@ -814,9 +813,7 @@ restart_int_handler: | |||
814 | lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone | 813 | lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone |
815 | stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on | 814 | stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on |
816 | jg start_secondary | 815 | jg start_secondary |
817 | #ifndef CONFIG_HOTPLUG_CPU | ||
818 | .previous | 816 | .previous |
819 | #endif | ||
820 | #else | 817 | #else |
821 | /* | 818 | /* |
822 | * If we do not run with SMP enabled, let the new CPU crash ... | 819 | * If we do not run with SMP enabled, let the new CPU crash ... |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index db28cca81fef..60acdc266db1 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -439,7 +439,7 @@ static void ipl_run(struct shutdown_trigger *trigger) | |||
439 | reipl_ccw_dev(&ipl_info.data.ccw.dev_id); | 439 | reipl_ccw_dev(&ipl_info.data.ccw.dev_id); |
440 | } | 440 | } |
441 | 441 | ||
442 | static int ipl_init(void) | 442 | static int __init ipl_init(void) |
443 | { | 443 | { |
444 | int rc; | 444 | int rc; |
445 | 445 | ||
@@ -471,8 +471,11 @@ out: | |||
471 | return 0; | 471 | return 0; |
472 | } | 472 | } |
473 | 473 | ||
474 | static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run, | 474 | static struct shutdown_action __refdata ipl_action = { |
475 | ipl_init}; | 475 | .name = SHUTDOWN_ACTION_IPL_STR, |
476 | .fn = ipl_run, | ||
477 | .init = ipl_init, | ||
478 | }; | ||
476 | 479 | ||
477 | /* | 480 | /* |
478 | * reipl shutdown action: Reboot Linux on shutdown. | 481 | * reipl shutdown action: Reboot Linux on shutdown. |
@@ -792,7 +795,7 @@ static int __init reipl_fcp_init(void) | |||
792 | return 0; | 795 | return 0; |
793 | } | 796 | } |
794 | 797 | ||
795 | static int reipl_init(void) | 798 | static int __init reipl_init(void) |
796 | { | 799 | { |
797 | int rc; | 800 | int rc; |
798 | 801 | ||
@@ -819,8 +822,11 @@ static int reipl_init(void) | |||
819 | return 0; | 822 | return 0; |
820 | } | 823 | } |
821 | 824 | ||
822 | static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR, | 825 | static struct shutdown_action __refdata reipl_action = { |
823 | reipl_run, reipl_init}; | 826 | .name = SHUTDOWN_ACTION_REIPL_STR, |
827 | .fn = reipl_run, | ||
828 | .init = reipl_init, | ||
829 | }; | ||
824 | 830 | ||
825 | /* | 831 | /* |
826 | * dump shutdown action: Dump Linux on shutdown. | 832 | * dump shutdown action: Dump Linux on shutdown. |
@@ -998,7 +1004,7 @@ static int __init dump_fcp_init(void) | |||
998 | return 0; | 1004 | return 0; |
999 | } | 1005 | } |
1000 | 1006 | ||
1001 | static int dump_init(void) | 1007 | static int __init dump_init(void) |
1002 | { | 1008 | { |
1003 | int rc; | 1009 | int rc; |
1004 | 1010 | ||
@@ -1020,8 +1026,11 @@ static int dump_init(void) | |||
1020 | return 0; | 1026 | return 0; |
1021 | } | 1027 | } |
1022 | 1028 | ||
1023 | static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR, | 1029 | static struct shutdown_action __refdata dump_action = { |
1024 | dump_run, dump_init}; | 1030 | .name = SHUTDOWN_ACTION_DUMP_STR, |
1031 | .fn = dump_run, | ||
1032 | .init = dump_init, | ||
1033 | }; | ||
1025 | 1034 | ||
1026 | /* | 1035 | /* |
1027 | * vmcmd shutdown action: Trigger vm command on shutdown. | 1036 | * vmcmd shutdown action: Trigger vm command on shutdown. |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 766c783bd7a7..29ae165d1749 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -77,7 +77,7 @@ unsigned long machine_flags = 0; | |||
77 | unsigned long elf_hwcap = 0; | 77 | unsigned long elf_hwcap = 0; |
78 | char elf_platform[ELF_PLATFORM_SIZE]; | 78 | char elf_platform[ELF_PLATFORM_SIZE]; |
79 | 79 | ||
80 | struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; | 80 | struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; |
81 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | 81 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ |
82 | static unsigned long __initdata memory_end; | 82 | static unsigned long __initdata memory_end; |
83 | 83 | ||
@@ -145,7 +145,7 @@ __setup("condev=", condev_setup); | |||
145 | 145 | ||
146 | static int __init conmode_setup(char *str) | 146 | static int __init conmode_setup(char *str) |
147 | { | 147 | { |
148 | #if defined(CONFIG_SCLP_CONSOLE) | 148 | #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) |
149 | if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) | 149 | if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) |
150 | SET_CONSOLE_SCLP; | 150 | SET_CONSOLE_SCLP; |
151 | #endif | 151 | #endif |
@@ -183,7 +183,7 @@ static void __init conmode_default(void) | |||
183 | */ | 183 | */ |
184 | cpcmd("TERM CONMODE 3215", NULL, 0, NULL); | 184 | cpcmd("TERM CONMODE 3215", NULL, 0, NULL); |
185 | if (ptr == NULL) { | 185 | if (ptr == NULL) { |
186 | #if defined(CONFIG_SCLP_CONSOLE) | 186 | #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) |
187 | SET_CONSOLE_SCLP; | 187 | SET_CONSOLE_SCLP; |
188 | #endif | 188 | #endif |
189 | return; | 189 | return; |
@@ -193,7 +193,7 @@ static void __init conmode_default(void) | |||
193 | SET_CONSOLE_3270; | 193 | SET_CONSOLE_3270; |
194 | #elif defined(CONFIG_TN3215_CONSOLE) | 194 | #elif defined(CONFIG_TN3215_CONSOLE) |
195 | SET_CONSOLE_3215; | 195 | SET_CONSOLE_3215; |
196 | #elif defined(CONFIG_SCLP_CONSOLE) | 196 | #elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) |
197 | SET_CONSOLE_SCLP; | 197 | SET_CONSOLE_SCLP; |
198 | #endif | 198 | #endif |
199 | } else if (strncmp(ptr + 8, "3215", 4) == 0) { | 199 | } else if (strncmp(ptr + 8, "3215", 4) == 0) { |
@@ -201,7 +201,7 @@ static void __init conmode_default(void) | |||
201 | SET_CONSOLE_3215; | 201 | SET_CONSOLE_3215; |
202 | #elif defined(CONFIG_TN3270_CONSOLE) | 202 | #elif defined(CONFIG_TN3270_CONSOLE) |
203 | SET_CONSOLE_3270; | 203 | SET_CONSOLE_3270; |
204 | #elif defined(CONFIG_SCLP_CONSOLE) | 204 | #elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) |
205 | SET_CONSOLE_SCLP; | 205 | SET_CONSOLE_SCLP; |
206 | #endif | 206 | #endif |
207 | } | 207 | } |
@@ -212,7 +212,7 @@ static void __init conmode_default(void) | |||
212 | SET_CONSOLE_3270; | 212 | SET_CONSOLE_3270; |
213 | #endif | 213 | #endif |
214 | } else { | 214 | } else { |
215 | #if defined(CONFIG_SCLP_CONSOLE) | 215 | #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) |
216 | SET_CONSOLE_SCLP; | 216 | SET_CONSOLE_SCLP; |
217 | #endif | 217 | #endif |
218 | } | 218 | } |
@@ -528,7 +528,7 @@ static void __init setup_memory_end(void) | |||
528 | memory_size = 0; | 528 | memory_size = 0; |
529 | memory_end &= PAGE_MASK; | 529 | memory_end &= PAGE_MASK; |
530 | 530 | ||
531 | max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START; | 531 | max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS; |
532 | memory_end = min(max_mem, memory_end); | 532 | memory_end = min(max_mem, memory_end); |
533 | 533 | ||
534 | /* | 534 | /* |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index aa37fa154512..85060659fb12 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -225,12 +225,11 @@ EXPORT_SYMBOL(smp_call_function_single); | |||
225 | * You must not call this function with disabled interrupts or from a | 225 | * You must not call this function with disabled interrupts or from a |
226 | * hardware interrupt handler or from a bottom half handler. | 226 | * hardware interrupt handler or from a bottom half handler. |
227 | */ | 227 | */ |
228 | int | 228 | int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, |
229 | smp_call_function_mask(cpumask_t mask, | 229 | int wait) |
230 | void (*func)(void *), void *info, | ||
231 | int wait) | ||
232 | { | 230 | { |
233 | preempt_disable(); | 231 | preempt_disable(); |
232 | cpu_clear(smp_processor_id(), mask); | ||
234 | __smp_call_function_map(func, info, 0, wait, mask); | 233 | __smp_call_function_map(func, info, 0, wait, mask); |
235 | preempt_enable(); | 234 | preempt_enable(); |
236 | return 0; | 235 | return 0; |
@@ -1008,7 +1007,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { | |||
1008 | .notifier_call = smp_cpu_notify, | 1007 | .notifier_call = smp_cpu_notify, |
1009 | }; | 1008 | }; |
1010 | 1009 | ||
1011 | static int smp_add_present_cpu(int cpu) | 1010 | static int __devinit smp_add_present_cpu(int cpu) |
1012 | { | 1011 | { |
1013 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 1012 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
1014 | struct sys_device *s = &c->sysdev; | 1013 | struct sys_device *s = &c->sysdev; |
@@ -1036,8 +1035,8 @@ out: | |||
1036 | } | 1035 | } |
1037 | 1036 | ||
1038 | #ifdef CONFIG_HOTPLUG_CPU | 1037 | #ifdef CONFIG_HOTPLUG_CPU |
1039 | static ssize_t rescan_store(struct sys_device *dev, const char *buf, | 1038 | static ssize_t __ref rescan_store(struct sys_device *dev, |
1040 | size_t count) | 1039 | const char *buf, size_t count) |
1041 | { | 1040 | { |
1042 | cpumask_t newcpus; | 1041 | cpumask_t newcpus; |
1043 | int cpu; | 1042 | int cpu; |
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index da6924729964..85e46a5d0e08 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c | |||
@@ -14,7 +14,8 @@ | |||
14 | static unsigned long save_context_stack(struct stack_trace *trace, | 14 | static unsigned long save_context_stack(struct stack_trace *trace, |
15 | unsigned long sp, | 15 | unsigned long sp, |
16 | unsigned long low, | 16 | unsigned long low, |
17 | unsigned long high) | 17 | unsigned long high, |
18 | int savesched) | ||
18 | { | 19 | { |
19 | struct stack_frame *sf; | 20 | struct stack_frame *sf; |
20 | struct pt_regs *regs; | 21 | struct pt_regs *regs; |
@@ -47,10 +48,12 @@ static unsigned long save_context_stack(struct stack_trace *trace, | |||
47 | return sp; | 48 | return sp; |
48 | regs = (struct pt_regs *)sp; | 49 | regs = (struct pt_regs *)sp; |
49 | addr = regs->psw.addr & PSW_ADDR_INSN; | 50 | addr = regs->psw.addr & PSW_ADDR_INSN; |
50 | if (!trace->skip) | 51 | if (savesched || !in_sched_functions(addr)) { |
51 | trace->entries[trace->nr_entries++] = addr; | 52 | if (!trace->skip) |
52 | else | 53 | trace->entries[trace->nr_entries++] = addr; |
53 | trace->skip--; | 54 | else |
55 | trace->skip--; | ||
56 | } | ||
54 | if (trace->nr_entries >= trace->max_entries) | 57 | if (trace->nr_entries >= trace->max_entries) |
55 | return sp; | 58 | return sp; |
56 | low = sp; | 59 | low = sp; |
@@ -66,15 +69,27 @@ void save_stack_trace(struct stack_trace *trace) | |||
66 | orig_sp = sp & PSW_ADDR_INSN; | 69 | orig_sp = sp & PSW_ADDR_INSN; |
67 | new_sp = save_context_stack(trace, orig_sp, | 70 | new_sp = save_context_stack(trace, orig_sp, |
68 | S390_lowcore.panic_stack - PAGE_SIZE, | 71 | S390_lowcore.panic_stack - PAGE_SIZE, |
69 | S390_lowcore.panic_stack); | 72 | S390_lowcore.panic_stack, 1); |
70 | if (new_sp != orig_sp) | 73 | if (new_sp != orig_sp) |
71 | return; | 74 | return; |
72 | new_sp = save_context_stack(trace, new_sp, | 75 | new_sp = save_context_stack(trace, new_sp, |
73 | S390_lowcore.async_stack - ASYNC_SIZE, | 76 | S390_lowcore.async_stack - ASYNC_SIZE, |
74 | S390_lowcore.async_stack); | 77 | S390_lowcore.async_stack, 1); |
75 | if (new_sp != orig_sp) | 78 | if (new_sp != orig_sp) |
76 | return; | 79 | return; |
77 | save_context_stack(trace, new_sp, | 80 | save_context_stack(trace, new_sp, |
78 | S390_lowcore.thread_info, | 81 | S390_lowcore.thread_info, |
79 | S390_lowcore.thread_info + THREAD_SIZE); | 82 | S390_lowcore.thread_info + THREAD_SIZE, 1); |
83 | } | ||
84 | |||
85 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
86 | { | ||
87 | unsigned long sp, low, high; | ||
88 | |||
89 | sp = tsk->thread.ksp & PSW_ADDR_INSN; | ||
90 | low = (unsigned long) task_stack_page(tsk); | ||
91 | high = (unsigned long) task_pt_regs(tsk); | ||
92 | save_context_stack(trace, sp, low, high, 0); | ||
93 | if (trace->nr_entries < trace->max_entries) | ||
94 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
80 | } | 95 | } |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 52b8342c6bf2..1a2fdb6991df 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -271,7 +271,10 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
271 | printk("PREEMPT "); | 271 | printk("PREEMPT "); |
272 | #endif | 272 | #endif |
273 | #ifdef CONFIG_SMP | 273 | #ifdef CONFIG_SMP |
274 | printk("SMP"); | 274 | printk("SMP "); |
275 | #endif | ||
276 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
277 | printk("DEBUG_PAGEALLOC"); | ||
275 | #endif | 278 | #endif |
276 | printk("\n"); | 279 | printk("\n"); |
277 | notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); | 280 | notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); |
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 7d43c3cd3ef3..b4607155e8d0 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S | |||
@@ -35,7 +35,7 @@ SECTIONS | |||
35 | KPROBES_TEXT | 35 | KPROBES_TEXT |
36 | *(.fixup) | 36 | *(.fixup) |
37 | *(.gnu.warning) | 37 | *(.gnu.warning) |
38 | } = 0x0700 | 38 | } :text = 0x0700 |
39 | 39 | ||
40 | _etext = .; /* End of text section */ | 40 | _etext = .; /* End of text section */ |
41 | 41 | ||
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index b234bb4a6da7..983ec6ec0e7c 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -167,6 +167,33 @@ void __init mem_init(void) | |||
167 | PFN_ALIGN((unsigned long)&_eshared) - 1); | 167 | PFN_ALIGN((unsigned long)&_eshared) - 1); |
168 | } | 168 | } |
169 | 169 | ||
170 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
171 | void kernel_map_pages(struct page *page, int numpages, int enable) | ||
172 | { | ||
173 | pgd_t *pgd; | ||
174 | pud_t *pud; | ||
175 | pmd_t *pmd; | ||
176 | pte_t *pte; | ||
177 | unsigned long address; | ||
178 | int i; | ||
179 | |||
180 | for (i = 0; i < numpages; i++) { | ||
181 | address = page_to_phys(page + i); | ||
182 | pgd = pgd_offset_k(address); | ||
183 | pud = pud_offset(pgd, address); | ||
184 | pmd = pmd_offset(pud, address); | ||
185 | pte = pte_offset_kernel(pmd, address); | ||
186 | if (!enable) { | ||
187 | ptep_invalidate(address, pte); | ||
188 | continue; | ||
189 | } | ||
190 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); | ||
191 | /* Flush cpu write queue. */ | ||
192 | mb(); | ||
193 | } | ||
194 | } | ||
195 | #endif | ||
196 | |||
170 | void free_initmem(void) | 197 | void free_initmem(void) |
171 | { | 198 | { |
172 | unsigned long addr; | 199 | unsigned long addr; |
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 79d13a166a3d..7c1287ccf788 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
@@ -62,7 +62,7 @@ void __meminit memmap_init(unsigned long size, int nid, unsigned long zone, | |||
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | static void __init_refok *vmem_alloc_pages(unsigned int order) | 65 | static void __ref *vmem_alloc_pages(unsigned int order) |
66 | { | 66 | { |
67 | if (slab_is_available()) | 67 | if (slab_is_available()) |
68 | return (void *)__get_free_pages(GFP_KERNEL, order); | 68 | return (void *)__get_free_pages(GFP_KERNEL, order); |
@@ -250,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg) | |||
250 | { | 250 | { |
251 | struct memory_segment *tmp; | 251 | struct memory_segment *tmp; |
252 | 252 | ||
253 | if (seg->start + seg->size >= VMALLOC_START || | 253 | if (seg->start + seg->size >= VMEM_MAX_PHYS || |
254 | seg->start + seg->size < seg->start) | 254 | seg->start + seg->size < seg->start) |
255 | return -ERANGE; | 255 | return -ERANGE; |
256 | 256 | ||
@@ -360,7 +360,6 @@ void __init vmem_map_init(void) | |||
360 | { | 360 | { |
361 | int i; | 361 | int i; |
362 | 362 | ||
363 | BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX); | ||
364 | NODE_DATA(0)->node_mem_map = VMEM_MAP; | 363 | NODE_DATA(0)->node_mem_map = VMEM_MAP; |
365 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) | 364 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) |
366 | vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); | 365 | vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d640427c74c8..d984e0fae630 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1057,12 +1057,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1057 | if (device->features & DASD_FEATURE_ERPLOG) { | 1057 | if (device->features & DASD_FEATURE_ERPLOG) { |
1058 | dasd_log_sense(cqr, irb); | 1058 | dasd_log_sense(cqr, irb); |
1059 | } | 1059 | } |
1060 | /* If we have no sense data, or we just don't want complex ERP | 1060 | /* |
1061 | * for this request, but if we have retries left, then just | 1061 | * If we don't want complex ERP for this request, then just |
1062 | * reset this request and retry it in the fastpath | 1062 | * reset this and retry it in the fastpath |
1063 | */ | 1063 | */ |
1064 | if (!(cqr->irb.esw.esw0.erw.cons && | 1064 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && |
1065 | test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) && | ||
1066 | cqr->retries > 0) { | 1065 | cqr->retries > 0) { |
1067 | DEV_MESSAGE(KERN_DEBUG, device, | 1066 | DEV_MESSAGE(KERN_DEBUG, device, |
1068 | "default ERP in fastpath (%i retries left)", | 1067 | "default ERP in fastpath (%i retries left)", |
@@ -1707,7 +1706,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) | |||
1707 | 1706 | ||
1708 | req = (struct request *) cqr->callback_data; | 1707 | req = (struct request *) cqr->callback_data; |
1709 | dasd_profile_end(cqr->block, cqr, req); | 1708 | dasd_profile_end(cqr->block, cqr, req); |
1710 | status = cqr->memdev->discipline->free_cp(cqr, req); | 1709 | status = cqr->block->base->discipline->free_cp(cqr, req); |
1711 | if (status <= 0) | 1710 | if (status <= 0) |
1712 | error = status ? status : -EIO; | 1711 | error = status ? status : -EIO; |
1713 | dasd_end_request(req, error); | 1712 | dasd_end_request(req, error); |
@@ -1742,12 +1741,8 @@ restart: | |||
1742 | 1741 | ||
1743 | /* Process requests that may be recovered */ | 1742 | /* Process requests that may be recovered */ |
1744 | if (cqr->status == DASD_CQR_NEED_ERP) { | 1743 | if (cqr->status == DASD_CQR_NEED_ERP) { |
1745 | if (cqr->irb.esw.esw0.erw.cons && | 1744 | erp_fn = base->discipline->erp_action(cqr); |
1746 | test_bit(DASD_CQR_FLAGS_USE_ERP, | 1745 | erp_fn(cqr); |
1747 | &cqr->flags)) { | ||
1748 | erp_fn = base->discipline->erp_action(cqr); | ||
1749 | erp_fn(cqr); | ||
1750 | } | ||
1751 | goto restart; | 1746 | goto restart; |
1752 | } | 1747 | } |
1753 | 1748 | ||
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index c361ab69ec00..f69714a0e9e7 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -164,7 +164,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) | |||
164 | 164 | ||
165 | /* reset status to submit the request again... */ | 165 | /* reset status to submit the request again... */ |
166 | erp->status = DASD_CQR_FILLED; | 166 | erp->status = DASD_CQR_FILLED; |
167 | erp->retries = 1; | 167 | erp->retries = 10; |
168 | } else { | 168 | } else { |
169 | DEV_MESSAGE(KERN_ERR, device, | 169 | DEV_MESSAGE(KERN_ERR, device, |
170 | "No alternate channel path left (lpum=%x / " | 170 | "No alternate channel path left (lpum=%x / " |
@@ -301,8 +301,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) | |||
301 | erp->function = dasd_3990_erp_action_4; | 301 | erp->function = dasd_3990_erp_action_4; |
302 | 302 | ||
303 | } else { | 303 | } else { |
304 | 304 | if (sense && (sense[25] == 0x1D)) { /* state change pending */ | |
305 | if (sense[25] == 0x1D) { /* state change pending */ | ||
306 | 305 | ||
307 | DEV_MESSAGE(KERN_INFO, device, | 306 | DEV_MESSAGE(KERN_INFO, device, |
308 | "waiting for state change pending " | 307 | "waiting for state change pending " |
@@ -311,7 +310,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) | |||
311 | 310 | ||
312 | dasd_3990_erp_block_queue(erp, 30*HZ); | 311 | dasd_3990_erp_block_queue(erp, 30*HZ); |
313 | 312 | ||
314 | } else if (sense[25] == 0x1E) { /* busy */ | 313 | } else if (sense && (sense[25] == 0x1E)) { /* busy */ |
315 | DEV_MESSAGE(KERN_INFO, device, | 314 | DEV_MESSAGE(KERN_INFO, device, |
316 | "busy - redriving request later, " | 315 | "busy - redriving request later, " |
317 | "%d retries left", | 316 | "%d retries left", |
@@ -2120,6 +2119,34 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) | |||
2120 | */ | 2119 | */ |
2121 | 2120 | ||
2122 | /* | 2121 | /* |
2122 | * DASD_3990_ERP_CONTROL_CHECK | ||
2123 | * | ||
2124 | * DESCRIPTION | ||
2125 | * Does a generic inspection if a control check occured and sets up | ||
2126 | * the related error recovery procedure | ||
2127 | * | ||
2128 | * PARAMETER | ||
2129 | * erp pointer to the currently created default ERP | ||
2130 | * | ||
2131 | * RETURN VALUES | ||
2132 | * erp_filled pointer to the erp | ||
2133 | */ | ||
2134 | |||
2135 | static struct dasd_ccw_req * | ||
2136 | dasd_3990_erp_control_check(struct dasd_ccw_req *erp) | ||
2137 | { | ||
2138 | struct dasd_device *device = erp->startdev; | ||
2139 | |||
2140 | if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | ||
2141 | | SCHN_STAT_CHN_CTRL_CHK)) { | ||
2142 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | ||
2143 | "channel or interface control check"); | ||
2144 | erp = dasd_3990_erp_action_4(erp, NULL); | ||
2145 | } | ||
2146 | return erp; | ||
2147 | } | ||
2148 | |||
2149 | /* | ||
2123 | * DASD_3990_ERP_INSPECT | 2150 | * DASD_3990_ERP_INSPECT |
2124 | * | 2151 | * |
2125 | * DESCRIPTION | 2152 | * DESCRIPTION |
@@ -2145,8 +2172,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | |||
2145 | if (erp_new) | 2172 | if (erp_new) |
2146 | return erp_new; | 2173 | return erp_new; |
2147 | 2174 | ||
2175 | /* check if no concurrent sens is available */ | ||
2176 | if (!erp->refers->irb.esw.esw0.erw.cons) | ||
2177 | erp_new = dasd_3990_erp_control_check(erp); | ||
2148 | /* distinguish between 24 and 32 byte sense data */ | 2178 | /* distinguish between 24 and 32 byte sense data */ |
2149 | if (sense[27] & DASD_SENSE_BIT_0) { | 2179 | else if (sense[27] & DASD_SENSE_BIT_0) { |
2150 | 2180 | ||
2151 | /* inspect the 24 byte sense data */ | 2181 | /* inspect the 24 byte sense data */ |
2152 | erp_new = dasd_3990_erp_inspect_24(erp, sense); | 2182 | erp_new = dasd_3990_erp_inspect_24(erp, sense); |
@@ -2285,6 +2315,17 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) | |||
2285 | // return 0; /* CCW doesn't match */ | 2315 | // return 0; /* CCW doesn't match */ |
2286 | } | 2316 | } |
2287 | 2317 | ||
2318 | if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) | ||
2319 | return 0; | ||
2320 | |||
2321 | if ((cqr1->irb.esw.esw0.erw.cons == 0) && | ||
2322 | (cqr2->irb.esw.esw0.erw.cons == 0)) { | ||
2323 | if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | | ||
2324 | SCHN_STAT_CHN_CTRL_CHK)) == | ||
2325 | (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | | ||
2326 | SCHN_STAT_CHN_CTRL_CHK))) | ||
2327 | return 1; /* match with ifcc*/ | ||
2328 | } | ||
2288 | /* check sense data; byte 0-2,25,27 */ | 2329 | /* check sense data; byte 0-2,25,27 */ |
2289 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && | 2330 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && |
2290 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && | 2331 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && |
@@ -2560,17 +2601,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) | |||
2560 | 2601 | ||
2561 | return cqr; | 2602 | return cqr; |
2562 | } | 2603 | } |
2563 | /* check if sense data are available */ | ||
2564 | if (!cqr->irb.ecw) { | ||
2565 | DEV_MESSAGE(KERN_DEBUG, device, | ||
2566 | "ERP called witout sense data avail ..." | ||
2567 | "request %p - NO ERP possible", cqr); | ||
2568 | |||
2569 | cqr->status = DASD_CQR_FAILED; | ||
2570 | |||
2571 | return cqr; | ||
2572 | |||
2573 | } | ||
2574 | 2604 | ||
2575 | /* check if error happened before */ | 2605 | /* check if error happened before */ |
2576 | erp = dasd_3990_erp_in_erp(cqr); | 2606 | erp = dasd_3990_erp_in_erp(cqr); |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 7779bfce1c31..3faf0538b328 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -415,6 +415,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
415 | dev_info->gd->queue = dev_info->dcssblk_queue; | 415 | dev_info->gd->queue = dev_info->dcssblk_queue; |
416 | dev_info->gd->private_data = dev_info; | 416 | dev_info->gd->private_data = dev_info; |
417 | dev_info->gd->driverfs_dev = &dev_info->dev; | 417 | dev_info->gd->driverfs_dev = &dev_info->dev; |
418 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | ||
419 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | ||
418 | /* | 420 | /* |
419 | * load the segment | 421 | * load the segment |
420 | */ | 422 | */ |
@@ -472,9 +474,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
472 | if (rc) | 474 | if (rc) |
473 | goto unregister_dev; | 475 | goto unregister_dev; |
474 | 476 | ||
475 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | ||
476 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | ||
477 | |||
478 | add_disk(dev_info->gd); | 477 | add_disk(dev_info->gd); |
479 | 478 | ||
480 | switch (dev_info->segment_type) { | 479 | switch (dev_info->segment_type) { |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..2e616e33891d 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
@@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count) | |||
332 | if (sclp_ttybuf == NULL) { | 332 | if (sclp_ttybuf == NULL) { |
333 | while (list_empty(&sclp_tty_pages)) { | 333 | while (list_empty(&sclp_tty_pages)) { |
334 | spin_unlock_irqrestore(&sclp_tty_lock, flags); | 334 | spin_unlock_irqrestore(&sclp_tty_lock, flags); |
335 | if (in_interrupt()) | 335 | if (in_atomic()) |
336 | sclp_sync_wait(); | 336 | sclp_sync_wait(); |
337 | else | 337 | else |
338 | wait_event(sclp_tty_waitq, | 338 | wait_event(sclp_tty_waitq, |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 40cd21bc5cc4..68071622d4bb 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -400,7 +400,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
400 | while (list_empty(&sclp_vt220_empty)) { | 400 | while (list_empty(&sclp_vt220_empty)) { |
401 | spin_unlock_irqrestore(&sclp_vt220_lock, | 401 | spin_unlock_irqrestore(&sclp_vt220_lock, |
402 | flags); | 402 | flags); |
403 | if (in_interrupt()) | 403 | if (in_atomic()) |
404 | sclp_sync_wait(); | 404 | sclp_sync_wait(); |
405 | else | 405 | else |
406 | wait_event(sclp_vt220_waitq, | 406 | wait_event(sclp_vt220_waitq, |
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 3964056a9a47..03914fa81174 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -391,12 +391,24 @@ ccwgroup_remove (struct device *dev) | |||
391 | return 0; | 391 | return 0; |
392 | } | 392 | } |
393 | 393 | ||
394 | static void ccwgroup_shutdown(struct device *dev) | ||
395 | { | ||
396 | struct ccwgroup_device *gdev; | ||
397 | struct ccwgroup_driver *gdrv; | ||
398 | |||
399 | gdev = to_ccwgroupdev(dev); | ||
400 | gdrv = to_ccwgroupdrv(dev->driver); | ||
401 | if (gdrv && gdrv->shutdown) | ||
402 | gdrv->shutdown(gdev); | ||
403 | } | ||
404 | |||
394 | static struct bus_type ccwgroup_bus_type = { | 405 | static struct bus_type ccwgroup_bus_type = { |
395 | .name = "ccwgroup", | 406 | .name = "ccwgroup", |
396 | .match = ccwgroup_bus_match, | 407 | .match = ccwgroup_bus_match, |
397 | .uevent = ccwgroup_uevent, | 408 | .uevent = ccwgroup_uevent, |
398 | .probe = ccwgroup_probe, | 409 | .probe = ccwgroup_probe, |
399 | .remove = ccwgroup_remove, | 410 | .remove = ccwgroup_remove, |
411 | .shutdown = ccwgroup_shutdown, | ||
400 | }; | 412 | }; |
401 | 413 | ||
402 | /** | 414 | /** |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e7ba16a74ef7..007aaeb4f532 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -26,6 +26,25 @@ | |||
26 | 26 | ||
27 | static void *sei_page; | 27 | static void *sei_page; |
28 | 28 | ||
29 | static int chsc_error_from_response(int response) | ||
30 | { | ||
31 | switch (response) { | ||
32 | case 0x0001: | ||
33 | return 0; | ||
34 | case 0x0002: | ||
35 | case 0x0003: | ||
36 | case 0x0006: | ||
37 | case 0x0007: | ||
38 | case 0x0008: | ||
39 | case 0x000a: | ||
40 | return -EINVAL; | ||
41 | case 0x0004: | ||
42 | return -EOPNOTSUPP; | ||
43 | default: | ||
44 | return -EIO; | ||
45 | } | ||
46 | } | ||
47 | |||
29 | struct chsc_ssd_area { | 48 | struct chsc_ssd_area { |
30 | struct chsc_header request; | 49 | struct chsc_header request; |
31 | u16 :10; | 50 | u16 :10; |
@@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) | |||
75 | ret = (ccode == 3) ? -ENODEV : -EBUSY; | 94 | ret = (ccode == 3) ? -ENODEV : -EBUSY; |
76 | goto out_free; | 95 | goto out_free; |
77 | } | 96 | } |
78 | if (ssd_area->response.code != 0x0001) { | 97 | ret = chsc_error_from_response(ssd_area->response.code); |
98 | if (ret != 0) { | ||
79 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", | 99 | CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", |
80 | schid.ssid, schid.sch_no, | 100 | schid.ssid, schid.sch_no, |
81 | ssd_area->response.code); | 101 | ssd_area->response.code); |
82 | ret = -EIO; | ||
83 | goto out_free; | 102 | goto out_free; |
84 | } | 103 | } |
85 | if (!ssd_area->sch_valid) { | 104 | if (!ssd_area->sch_valid) { |
@@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) | |||
717 | return (ccode == 3) ? -ENODEV : -EBUSY; | 736 | return (ccode == 3) ? -ENODEV : -EBUSY; |
718 | 737 | ||
719 | switch (secm_area->response.code) { | 738 | switch (secm_area->response.code) { |
720 | case 0x0001: /* Success. */ | 739 | case 0x0102: |
721 | ret = 0; | 740 | case 0x0103: |
722 | break; | ||
723 | case 0x0003: /* Invalid block. */ | ||
724 | case 0x0007: /* Invalid format. */ | ||
725 | case 0x0008: /* Other invalid block. */ | ||
726 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
727 | ret = -EINVAL; | ||
728 | break; | ||
729 | case 0x0004: /* Command not provided in model. */ | ||
730 | CIO_CRW_EVENT(2, "Model does not provide secm\n"); | ||
731 | ret = -EOPNOTSUPP; | ||
732 | break; | ||
733 | case 0x0102: /* cub adresses incorrect */ | ||
734 | CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n"); | ||
735 | ret = -EINVAL; | ||
736 | break; | ||
737 | case 0x0103: /* key error */ | ||
738 | CIO_CRW_EVENT(2, "Access key error in secm\n"); | ||
739 | ret = -EINVAL; | 741 | ret = -EINVAL; |
740 | break; | ||
741 | case 0x0105: /* error while starting */ | ||
742 | CIO_CRW_EVENT(2, "Error while starting channel measurement\n"); | ||
743 | ret = -EIO; | ||
744 | break; | ||
745 | default: | 742 | default: |
746 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | 743 | ret = chsc_error_from_response(secm_area->response.code); |
747 | secm_area->response.code); | ||
748 | ret = -EIO; | ||
749 | } | 744 | } |
745 | if (ret != 0) | ||
746 | CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", | ||
747 | secm_area->response.code); | ||
750 | return ret; | 748 | return ret; |
751 | } | 749 | } |
752 | 750 | ||
@@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid, | |||
827 | goto out; | 825 | goto out; |
828 | } | 826 | } |
829 | 827 | ||
830 | switch (scpd_area->response.code) { | 828 | ret = chsc_error_from_response(scpd_area->response.code); |
831 | case 0x0001: /* Success. */ | 829 | if (ret == 0) |
830 | /* Success. */ | ||
832 | memcpy(desc, &scpd_area->desc, | 831 | memcpy(desc, &scpd_area->desc, |
833 | sizeof(struct channel_path_desc)); | 832 | sizeof(struct channel_path_desc)); |
834 | ret = 0; | 833 | else |
835 | break; | 834 | CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", |
836 | case 0x0003: /* Invalid block. */ | ||
837 | case 0x0007: /* Invalid format. */ | ||
838 | case 0x0008: /* Other invalid block. */ | ||
839 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
840 | ret = -EINVAL; | ||
841 | break; | ||
842 | case 0x0004: /* Command not provided in model. */ | ||
843 | CIO_CRW_EVENT(2, "Model does not provide scpd\n"); | ||
844 | ret = -EOPNOTSUPP; | ||
845 | break; | ||
846 | default: | ||
847 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
848 | scpd_area->response.code); | 835 | scpd_area->response.code); |
849 | ret = -EIO; | ||
850 | } | ||
851 | out: | 836 | out: |
852 | free_page((unsigned long)scpd_area); | 837 | free_page((unsigned long)scpd_area); |
853 | return ret; | 838 | return ret; |
@@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
923 | goto out; | 908 | goto out; |
924 | } | 909 | } |
925 | 910 | ||
926 | switch (scmc_area->response.code) { | 911 | ret = chsc_error_from_response(scmc_area->response.code); |
927 | case 0x0001: /* Success. */ | 912 | if (ret == 0) { |
913 | /* Success. */ | ||
928 | if (!scmc_area->not_valid) { | 914 | if (!scmc_area->not_valid) { |
929 | chp->cmg = scmc_area->cmg; | 915 | chp->cmg = scmc_area->cmg; |
930 | chp->shared = scmc_area->shared; | 916 | chp->shared = scmc_area->shared; |
@@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) | |||
935 | chp->cmg = -1; | 921 | chp->cmg = -1; |
936 | chp->shared = -1; | 922 | chp->shared = -1; |
937 | } | 923 | } |
938 | ret = 0; | 924 | } else { |
939 | break; | 925 | CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n", |
940 | case 0x0003: /* Invalid block. */ | ||
941 | case 0x0007: /* Invalid format. */ | ||
942 | case 0x0008: /* Invalid bit combination. */ | ||
943 | CIO_CRW_EVENT(2, "Error in chsc request block!\n"); | ||
944 | ret = -EINVAL; | ||
945 | break; | ||
946 | case 0x0004: /* Command not provided. */ | ||
947 | CIO_CRW_EVENT(2, "Model does not provide scmc\n"); | ||
948 | ret = -EOPNOTSUPP; | ||
949 | break; | ||
950 | default: | ||
951 | CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", | ||
952 | scmc_area->response.code); | 926 | scmc_area->response.code); |
953 | ret = -EIO; | ||
954 | } | 927 | } |
955 | out: | 928 | out: |
956 | free_page((unsigned long)scmc_area); | 929 | free_page((unsigned long)scmc_area); |
@@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code) | |||
1002 | ret = (ret == 3) ? -ENODEV : -EBUSY; | 975 | ret = (ret == 3) ? -ENODEV : -EBUSY; |
1003 | goto out; | 976 | goto out; |
1004 | } | 977 | } |
978 | |||
1005 | switch (sda_area->response.code) { | 979 | switch (sda_area->response.code) { |
1006 | case 0x0001: /* everything ok */ | 980 | case 0x0101: |
1007 | ret = 0; | ||
1008 | break; | ||
1009 | case 0x0003: /* invalid request block */ | ||
1010 | case 0x0007: | ||
1011 | ret = -EINVAL; | ||
1012 | break; | ||
1013 | case 0x0004: /* command not provided */ | ||
1014 | case 0x0101: /* facility not provided */ | ||
1015 | ret = -EOPNOTSUPP; | 981 | ret = -EOPNOTSUPP; |
1016 | break; | 982 | break; |
1017 | default: /* something went wrong */ | 983 | default: |
1018 | ret = -EIO; | 984 | ret = chsc_error_from_response(sda_area->response.code); |
1019 | } | 985 | } |
986 | if (ret != 0) | ||
987 | CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", | ||
988 | operation_code, sda_area->response.code); | ||
1020 | out: | 989 | out: |
1021 | free_page((unsigned long)sda_area); | 990 | free_page((unsigned long)sda_area); |
1022 | return ret; | 991 | return ret; |
@@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void) | |||
1041 | } __attribute__ ((packed)) *scsc_area; | 1010 | } __attribute__ ((packed)) *scsc_area; |
1042 | 1011 | ||
1043 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 1012 | scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
1044 | if (!scsc_area) { | 1013 | if (!scsc_area) |
1045 | CIO_MSG_EVENT(0, "Was not able to determine available " | ||
1046 | "CHSCs due to no memory.\n"); | ||
1047 | return -ENOMEM; | 1014 | return -ENOMEM; |
1048 | } | ||
1049 | 1015 | ||
1050 | scsc_area->request.length = 0x0010; | 1016 | scsc_area->request.length = 0x0010; |
1051 | scsc_area->request.code = 0x0010; | 1017 | scsc_area->request.code = 0x0010; |
1052 | 1018 | ||
1053 | result = chsc(scsc_area); | 1019 | result = chsc(scsc_area); |
1054 | if (result) { | 1020 | if (result) { |
1055 | CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, " | 1021 | result = (result == 3) ? -ENODEV : -EBUSY; |
1056 | "cc=%i.\n", result); | ||
1057 | result = -EIO; | ||
1058 | goto exit; | 1022 | goto exit; |
1059 | } | 1023 | } |
1060 | 1024 | ||
1061 | if (scsc_area->response.code != 1) { | 1025 | result = chsc_error_from_response(scsc_area->response.code); |
1062 | CIO_MSG_EVENT(0, "Was not able to determine " | 1026 | if (result == 0) { |
1063 | "available CHSCs.\n"); | 1027 | memcpy(&css_general_characteristics, scsc_area->general_char, |
1064 | result = -EIO; | 1028 | sizeof(css_general_characteristics)); |
1065 | goto exit; | 1029 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, |
1066 | } | 1030 | sizeof(css_chsc_characteristics)); |
1067 | memcpy(&css_general_characteristics, scsc_area->general_char, | 1031 | } else |
1068 | sizeof(css_general_characteristics)); | 1032 | CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", |
1069 | memcpy(&css_chsc_characteristics, scsc_area->chsc_char, | 1033 | scsc_area->response.code); |
1070 | sizeof(css_chsc_characteristics)); | ||
1071 | exit: | 1034 | exit: |
1072 | free_page ((unsigned long) scsc_area); | 1035 | free_page ((unsigned long) scsc_area); |
1073 | return result; | 1036 | return result; |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 918b8b89cf9a..dc4d87f77f6c 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -26,17 +26,18 @@ | |||
26 | #include "ioasm.h" | 26 | #include "ioasm.h" |
27 | #include "io_sch.h" | 27 | #include "io_sch.h" |
28 | 28 | ||
29 | /* | 29 | /** |
30 | * Input : | 30 | * vm_vdev_to_cu_type - Convert vm virtual device into control unit type |
31 | * devno - device number | 31 | * for certain devices. |
32 | * ps - pointer to sense ID data area | 32 | * @class: virtual device class |
33 | * Output : none | 33 | * @type: virtual device type |
34 | * | ||
35 | * Returns control unit type if a match was made or %0xffff otherwise. | ||
34 | */ | 36 | */ |
35 | static void | 37 | static int vm_vdev_to_cu_type(int class, int type) |
36 | VM_virtual_device_info (__u16 devno, struct senseid *ps) | ||
37 | { | 38 | { |
38 | static struct { | 39 | static struct { |
39 | int vrdcvcla, vrdcvtyp, cu_type; | 40 | int class, type, cu_type; |
40 | } vm_devices[] = { | 41 | } vm_devices[] = { |
41 | { 0x08, 0x01, 0x3480 }, | 42 | { 0x08, 0x01, 0x3480 }, |
42 | { 0x08, 0x02, 0x3430 }, | 43 | { 0x08, 0x02, 0x3430 }, |
@@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
68 | { 0x40, 0xc0, 0x5080 }, | 69 | { 0x40, 0xc0, 0x5080 }, |
69 | { 0x80, 0x00, 0x3215 }, | 70 | { 0x80, 0x00, 0x3215 }, |
70 | }; | 71 | }; |
72 | int i; | ||
73 | |||
74 | for (i = 0; i < ARRAY_SIZE(vm_devices); i++) | ||
75 | if (class == vm_devices[i].class && type == vm_devices[i].type) | ||
76 | return vm_devices[i].cu_type; | ||
77 | |||
78 | return 0xffff; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * diag_get_dev_info - retrieve device information via DIAG X'210' | ||
83 | * @devno: device number | ||
84 | * @ps: pointer to sense ID data area | ||
85 | * | ||
86 | * Returns zero on success, non-zero otherwise. | ||
87 | */ | ||
88 | static int diag_get_dev_info(u16 devno, struct senseid *ps) | ||
89 | { | ||
71 | struct diag210 diag_data; | 90 | struct diag210 diag_data; |
72 | int ccode, i; | 91 | int ccode; |
73 | 92 | ||
74 | CIO_TRACE_EVENT (4, "VMvdinf"); | 93 | CIO_TRACE_EVENT (4, "VMvdinf"); |
75 | 94 | ||
@@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
79 | }; | 98 | }; |
80 | 99 | ||
81 | ccode = diag210 (&diag_data); | 100 | ccode = diag210 (&diag_data); |
82 | ps->reserved = 0xff; | 101 | if ((ccode == 0) || (ccode == 2)) { |
102 | ps->reserved = 0xff; | ||
83 | 103 | ||
84 | /* Special case for bloody osa devices. */ | 104 | /* Special case for osa devices. */ |
85 | if (diag_data.vrdcvcla == 0x02 && | 105 | if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) { |
86 | diag_data.vrdcvtyp == 0x20) { | 106 | ps->cu_type = 0x3088; |
87 | ps->cu_type = 0x3088; | 107 | ps->cu_model = 0x60; |
88 | ps->cu_model = 0x60; | 108 | return 0; |
89 | return; | ||
90 | } | ||
91 | for (i = 0; i < ARRAY_SIZE(vm_devices); i++) | ||
92 | if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla && | ||
93 | diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) { | ||
94 | ps->cu_type = vm_devices[i].cu_type; | ||
95 | return; | ||
96 | } | 109 | } |
110 | ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla, | ||
111 | diag_data.vrdcvtyp); | ||
112 | if (ps->cu_type != 0xffff) | ||
113 | return 0; | ||
114 | } | ||
115 | |||
97 | CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" | 116 | CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" |
98 | "vdev class : %02X, vdev type : %04X \n ... " | 117 | "vdev class : %02X, vdev type : %04X \n ... " |
99 | "rdev class : %02X, rdev type : %04X, " | 118 | "rdev class : %02X, rdev type : %04X, " |
@@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) | |||
102 | diag_data.vrdcvcla, diag_data.vrdcvtyp, | 121 | diag_data.vrdcvcla, diag_data.vrdcvtyp, |
103 | diag_data.vrdcrccl, diag_data.vrdccrty, | 122 | diag_data.vrdcrccl, diag_data.vrdccrty, |
104 | diag_data.vrdccrmd); | 123 | diag_data.vrdccrmd); |
124 | |||
125 | return -ENODEV; | ||
105 | } | 126 | } |
106 | 127 | ||
107 | /* | 128 | /* |
@@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
130 | /* Try on every path. */ | 151 | /* Try on every path. */ |
131 | ret = -ENODEV; | 152 | ret = -ENODEV; |
132 | while (cdev->private->imask != 0) { | 153 | while (cdev->private->imask != 0) { |
154 | cdev->private->senseid.cu_type = 0xFFFF; | ||
133 | if ((sch->opm & cdev->private->imask) != 0 && | 155 | if ((sch->opm & cdev->private->imask) != 0 && |
134 | cdev->private->iretry > 0) { | 156 | cdev->private->iretry > 0) { |
135 | cdev->private->iretry--; | 157 | cdev->private->iretry--; |
@@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev) | |||
153 | int ret; | 175 | int ret; |
154 | 176 | ||
155 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); | 177 | memset (&cdev->private->senseid, 0, sizeof (struct senseid)); |
156 | cdev->private->senseid.cu_type = 0xFFFF; | ||
157 | cdev->private->imask = 0x80; | 178 | cdev->private->imask = 0x80; |
158 | cdev->private->iretry = 5; | 179 | cdev->private->iretry = 5; |
159 | ret = __ccw_device_sense_id_start(cdev); | 180 | ret = __ccw_device_sense_id_start(cdev); |
@@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
173 | 194 | ||
174 | sch = to_subchannel(cdev->dev.parent); | 195 | sch = to_subchannel(cdev->dev.parent); |
175 | irb = &cdev->private->irb; | 196 | irb = &cdev->private->irb; |
176 | /* Did we get a proper answer ? */ | 197 | |
177 | if (cdev->private->senseid.cu_type != 0xFFFF && | ||
178 | cdev->private->senseid.reserved == 0xFF) { | ||
179 | if (irb->scsw.count < sizeof (struct senseid) - 8) | ||
180 | cdev->private->flags.esid = 1; | ||
181 | return 0; /* Success */ | ||
182 | } | ||
183 | /* Check the error cases. */ | 198 | /* Check the error cases. */ |
184 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { | 199 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
185 | /* Retry Sense ID if requested. */ | 200 | /* Retry Sense ID if requested. */ |
@@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
231 | sch->schid.ssid, sch->schid.sch_no); | 246 | sch->schid.ssid, sch->schid.sch_no); |
232 | return -EACCES; | 247 | return -EACCES; |
233 | } | 248 | } |
249 | |||
250 | /* Did we get a proper answer ? */ | ||
251 | if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && | ||
252 | cdev->private->senseid.reserved == 0xFF) { | ||
253 | if (irb->scsw.count < sizeof(struct senseid) - 8) | ||
254 | cdev->private->flags.esid = 1; | ||
255 | return 0; /* Success */ | ||
256 | } | ||
257 | |||
234 | /* Hmm, whatever happened, try again. */ | 258 | /* Hmm, whatever happened, try again. */ |
235 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " | 259 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " |
236 | "subchannel 0.%x.%04x returns status %02X%02X\n", | 260 | "subchannel 0.%x.%04x returns status %02X%02X\n", |
@@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
283 | break; | 307 | break; |
284 | /* fall through. */ | 308 | /* fall through. */ |
285 | default: /* Sense ID failed. Try asking VM. */ | 309 | default: /* Sense ID failed. Try asking VM. */ |
286 | if (MACHINE_IS_VM) { | 310 | if (MACHINE_IS_VM) |
287 | VM_virtual_device_info (cdev->private->dev_id.devno, | 311 | ret = diag_get_dev_info(cdev->private->dev_id.devno, |
288 | &cdev->private->senseid); | 312 | &cdev->private->senseid); |
289 | if (cdev->private->senseid.cu_type != 0xFFFF) { | 313 | else |
290 | /* Got the device information from VM. */ | 314 | /* |
291 | ccw_device_sense_id_done(cdev, 0); | 315 | * If we can't couldn't identify the device type we |
292 | return; | 316 | * consider the device "not operational". |
293 | } | 317 | */ |
294 | } | 318 | ret = -ENODEV; |
295 | /* | 319 | |
296 | * If we can't couldn't identify the device type we | 320 | ccw_device_sense_id_done(cdev, ret); |
297 | * consider the device "not operational". | ||
298 | */ | ||
299 | ccw_device_sense_id_done(cdev, -ENODEV); | ||
300 | break; | 321 | break; |
301 | } | 322 | } |
302 | } | 323 | } |
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index dba6fecad0be..882db054110c 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h | |||
@@ -440,242 +440,256 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) { | |||
440 | __test_bit((nr),(addr)) ) | 440 | __test_bit((nr),(addr)) ) |
441 | 441 | ||
442 | /* | 442 | /* |
443 | * ffz = Find First Zero in word. Undefined if no zero exists, | 443 | * Optimized find bit helper functions. |
444 | * so code should check against ~0UL first.. | ||
445 | */ | 444 | */ |
446 | static inline unsigned long ffz(unsigned long word) | 445 | |
446 | /** | ||
447 | * __ffz_word_loop - find byte offset of first long != -1UL | ||
448 | * @addr: pointer to array of unsigned long | ||
449 | * @size: size of the array in bits | ||
450 | */ | ||
451 | static inline unsigned long __ffz_word_loop(const unsigned long *addr, | ||
452 | unsigned long size) | ||
447 | { | 453 | { |
448 | unsigned long bit = 0; | 454 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; |
455 | unsigned long bytes = 0; | ||
449 | 456 | ||
457 | asm volatile( | ||
458 | #ifndef __s390x__ | ||
459 | " ahi %1,31\n" | ||
460 | " srl %1,5\n" | ||
461 | "0: c %2,0(%0,%3)\n" | ||
462 | " jne 1f\n" | ||
463 | " la %0,4(%0)\n" | ||
464 | " brct %1,0b\n" | ||
465 | "1:\n" | ||
466 | #else | ||
467 | " aghi %1,63\n" | ||
468 | " srlg %1,%1,6\n" | ||
469 | "0: cg %2,0(%0,%3)\n" | ||
470 | " jne 1f\n" | ||
471 | " la %0,8(%0)\n" | ||
472 | " brct %1,0b\n" | ||
473 | "1:\n" | ||
474 | #endif | ||
475 | : "+a" (bytes), "+d" (size) | ||
476 | : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr) | ||
477 | : "cc" ); | ||
478 | return bytes; | ||
479 | } | ||
480 | |||
481 | /** | ||
482 | * __ffs_word_loop - find byte offset of first long != 0UL | ||
483 | * @addr: pointer to array of unsigned long | ||
484 | * @size: size of the array in bits | ||
485 | */ | ||
486 | static inline unsigned long __ffs_word_loop(const unsigned long *addr, | ||
487 | unsigned long size) | ||
488 | { | ||
489 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | ||
490 | unsigned long bytes = 0; | ||
491 | |||
492 | asm volatile( | ||
493 | #ifndef __s390x__ | ||
494 | " ahi %1,31\n" | ||
495 | " srl %1,5\n" | ||
496 | "0: c %2,0(%0,%3)\n" | ||
497 | " jne 1f\n" | ||
498 | " la %0,4(%0)\n" | ||
499 | " brct %1,0b\n" | ||
500 | "1:\n" | ||
501 | #else | ||
502 | " aghi %1,63\n" | ||
503 | " srlg %1,%1,6\n" | ||
504 | "0: cg %2,0(%0,%3)\n" | ||
505 | " jne 1f\n" | ||
506 | " la %0,8(%0)\n" | ||
507 | " brct %1,0b\n" | ||
508 | "1:\n" | ||
509 | #endif | ||
510 | : "+a" (bytes), "+a" (size) | ||
511 | : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr) | ||
512 | : "cc" ); | ||
513 | return bytes; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * __ffz_word - add number of the first unset bit | ||
518 | * @nr: base value the bit number is added to | ||
519 | * @word: the word that is searched for unset bits | ||
520 | */ | ||
521 | static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) | ||
522 | { | ||
450 | #ifdef __s390x__ | 523 | #ifdef __s390x__ |
451 | if (likely((word & 0xffffffff) == 0xffffffff)) { | 524 | if (likely((word & 0xffffffff) == 0xffffffff)) { |
452 | word >>= 32; | 525 | word >>= 32; |
453 | bit += 32; | 526 | nr += 32; |
454 | } | 527 | } |
455 | #endif | 528 | #endif |
456 | if (likely((word & 0xffff) == 0xffff)) { | 529 | if (likely((word & 0xffff) == 0xffff)) { |
457 | word >>= 16; | 530 | word >>= 16; |
458 | bit += 16; | 531 | nr += 16; |
459 | } | 532 | } |
460 | if (likely((word & 0xff) == 0xff)) { | 533 | if (likely((word & 0xff) == 0xff)) { |
461 | word >>= 8; | 534 | word >>= 8; |
462 | bit += 8; | 535 | nr += 8; |
463 | } | 536 | } |
464 | return bit + _zb_findmap[word & 0xff]; | 537 | return nr + _zb_findmap[(unsigned char) word]; |
465 | } | 538 | } |
466 | 539 | ||
467 | /* | 540 | /** |
468 | * __ffs = find first bit in word. Undefined if no bit exists, | 541 | * __ffs_word - add number of the first set bit |
469 | * so code should check against 0UL first.. | 542 | * @nr: base value the bit number is added to |
543 | * @word: the word that is searched for set bits | ||
470 | */ | 544 | */ |
471 | static inline unsigned long __ffs (unsigned long word) | 545 | static inline unsigned long __ffs_word(unsigned long nr, unsigned long word) |
472 | { | 546 | { |
473 | unsigned long bit = 0; | ||
474 | |||
475 | #ifdef __s390x__ | 547 | #ifdef __s390x__ |
476 | if (likely((word & 0xffffffff) == 0)) { | 548 | if (likely((word & 0xffffffff) == 0)) { |
477 | word >>= 32; | 549 | word >>= 32; |
478 | bit += 32; | 550 | nr += 32; |
479 | } | 551 | } |
480 | #endif | 552 | #endif |
481 | if (likely((word & 0xffff) == 0)) { | 553 | if (likely((word & 0xffff) == 0)) { |
482 | word >>= 16; | 554 | word >>= 16; |
483 | bit += 16; | 555 | nr += 16; |
484 | } | 556 | } |
485 | if (likely((word & 0xff) == 0)) { | 557 | if (likely((word & 0xff) == 0)) { |
486 | word >>= 8; | 558 | word >>= 8; |
487 | bit += 8; | 559 | nr += 8; |
488 | } | 560 | } |
489 | return bit + _sb_findmap[word & 0xff]; | 561 | return nr + _sb_findmap[(unsigned char) word]; |
490 | } | 562 | } |
491 | 563 | ||
492 | /* | ||
493 | * Find-bit routines.. | ||
494 | */ | ||
495 | 564 | ||
496 | #ifndef __s390x__ | 565 | /** |
566 | * __load_ulong_be - load big endian unsigned long | ||
567 | * @p: pointer to array of unsigned long | ||
568 | * @offset: byte offset of source value in the array | ||
569 | */ | ||
570 | static inline unsigned long __load_ulong_be(const unsigned long *p, | ||
571 | unsigned long offset) | ||
572 | { | ||
573 | p = (unsigned long *)((unsigned long) p + offset); | ||
574 | return *p; | ||
575 | } | ||
497 | 576 | ||
498 | static inline int | 577 | /** |
499 | find_first_zero_bit(const unsigned long * addr, unsigned long size) | 578 | * __load_ulong_le - load little endian unsigned long |
579 | * @p: pointer to array of unsigned long | ||
580 | * @offset: byte offset of source value in the array | ||
581 | */ | ||
582 | static inline unsigned long __load_ulong_le(const unsigned long *p, | ||
583 | unsigned long offset) | ||
500 | { | 584 | { |
501 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 585 | unsigned long word; |
502 | unsigned long cmp, count; | ||
503 | unsigned int res; | ||
504 | 586 | ||
505 | if (!size) | 587 | p = (unsigned long *)((unsigned long) p + offset); |
506 | return 0; | 588 | #ifndef __s390x__ |
507 | asm volatile( | 589 | asm volatile( |
508 | " lhi %1,-1\n" | 590 | " ic %0,0(%1)\n" |
509 | " lr %2,%3\n" | 591 | " icm %0,2,1(%1)\n" |
510 | " slr %0,%0\n" | 592 | " icm %0,4,2(%1)\n" |
511 | " ahi %2,31\n" | 593 | " icm %0,8,3(%1)" |
512 | " srl %2,5\n" | 594 | : "=&d" (word) : "a" (p), "m" (*p) : "cc"); |
513 | "0: c %1,0(%0,%4)\n" | 595 | #else |
514 | " jne 1f\n" | 596 | asm volatile( |
515 | " la %0,4(%0)\n" | 597 | " lrvg %0,%1" |
516 | " brct %2,0b\n" | 598 | : "=d" (word) : "m" (*p) ); |
517 | " lr %0,%3\n" | 599 | #endif |
518 | " j 4f\n" | 600 | return word; |
519 | "1: l %2,0(%0,%4)\n" | ||
520 | " sll %0,3\n" | ||
521 | " lhi %1,0xff\n" | ||
522 | " tml %2,0xffff\n" | ||
523 | " jno 2f\n" | ||
524 | " ahi %0,16\n" | ||
525 | " srl %2,16\n" | ||
526 | "2: tml %2,0x00ff\n" | ||
527 | " jno 3f\n" | ||
528 | " ahi %0,8\n" | ||
529 | " srl %2,8\n" | ||
530 | "3: nr %2,%1\n" | ||
531 | " ic %2,0(%2,%5)\n" | ||
532 | " alr %0,%2\n" | ||
533 | "4:" | ||
534 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
535 | : "a" (size), "a" (addr), "a" (&_zb_findmap), | ||
536 | "m" (*(addrtype *) addr) : "cc"); | ||
537 | return (res < size) ? res : size; | ||
538 | } | 601 | } |
539 | 602 | ||
540 | static inline int | 603 | /* |
541 | find_first_bit(const unsigned long * addr, unsigned long size) | 604 | * The various find bit functions. |
605 | */ | ||
606 | |||
607 | /* | ||
608 | * ffz - find first zero in word. | ||
609 | * @word: The word to search | ||
610 | * | ||
611 | * Undefined if no zero exists, so code should check against ~0UL first. | ||
612 | */ | ||
613 | static inline unsigned long ffz(unsigned long word) | ||
542 | { | 614 | { |
543 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 615 | return __ffz_word(0, word); |
544 | unsigned long cmp, count; | 616 | } |
545 | unsigned int res; | ||
546 | 617 | ||
547 | if (!size) | 618 | /** |
548 | return 0; | 619 | * __ffs - find first bit in word. |
549 | asm volatile( | 620 | * @word: The word to search |
550 | " slr %1,%1\n" | 621 | * |
551 | " lr %2,%3\n" | 622 | * Undefined if no bit exists, so code should check against 0 first. |
552 | " slr %0,%0\n" | 623 | */ |
553 | " ahi %2,31\n" | 624 | static inline unsigned long __ffs (unsigned long word) |
554 | " srl %2,5\n" | 625 | { |
555 | "0: c %1,0(%0,%4)\n" | 626 | return __ffs_word(0, word); |
556 | " jne 1f\n" | ||
557 | " la %0,4(%0)\n" | ||
558 | " brct %2,0b\n" | ||
559 | " lr %0,%3\n" | ||
560 | " j 4f\n" | ||
561 | "1: l %2,0(%0,%4)\n" | ||
562 | " sll %0,3\n" | ||
563 | " lhi %1,0xff\n" | ||
564 | " tml %2,0xffff\n" | ||
565 | " jnz 2f\n" | ||
566 | " ahi %0,16\n" | ||
567 | " srl %2,16\n" | ||
568 | "2: tml %2,0x00ff\n" | ||
569 | " jnz 3f\n" | ||
570 | " ahi %0,8\n" | ||
571 | " srl %2,8\n" | ||
572 | "3: nr %2,%1\n" | ||
573 | " ic %2,0(%2,%5)\n" | ||
574 | " alr %0,%2\n" | ||
575 | "4:" | ||
576 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
577 | : "a" (size), "a" (addr), "a" (&_sb_findmap), | ||
578 | "m" (*(addrtype *) addr) : "cc"); | ||
579 | return (res < size) ? res : size; | ||
580 | } | 627 | } |
581 | 628 | ||
582 | #else /* __s390x__ */ | 629 | /** |
630 | * ffs - find first bit set | ||
631 | * @x: the word to search | ||
632 | * | ||
633 | * This is defined the same way as | ||
634 | * the libc and compiler builtin ffs routines, therefore | ||
635 | * differs in spirit from the above ffz (man ffs). | ||
636 | */ | ||
637 | static inline int ffs(int x) | ||
638 | { | ||
639 | if (!x) | ||
640 | return 0; | ||
641 | return __ffs_word(1, x); | ||
642 | } | ||
583 | 643 | ||
584 | static inline unsigned long | 644 | /** |
585 | find_first_zero_bit(const unsigned long * addr, unsigned long size) | 645 | * find_first_zero_bit - find the first zero bit in a memory region |
646 | * @addr: The address to start the search at | ||
647 | * @size: The maximum size to search | ||
648 | * | ||
649 | * Returns the bit-number of the first zero bit, not the number of the byte | ||
650 | * containing a bit. | ||
651 | */ | ||
652 | static inline unsigned long find_first_zero_bit(const unsigned long *addr, | ||
653 | unsigned long size) | ||
586 | { | 654 | { |
587 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 655 | unsigned long bytes, bits; |
588 | unsigned long res, cmp, count; | ||
589 | 656 | ||
590 | if (!size) | 657 | if (!size) |
591 | return 0; | 658 | return 0; |
592 | asm volatile( | 659 | bytes = __ffz_word_loop(addr, size); |
593 | " lghi %1,-1\n" | 660 | bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes)); |
594 | " lgr %2,%3\n" | 661 | return (bits < size) ? bits : size; |
595 | " slgr %0,%0\n" | 662 | } |
596 | " aghi %2,63\n" | 663 | |
597 | " srlg %2,%2,6\n" | 664 | /** |
598 | "0: cg %1,0(%0,%4)\n" | 665 | * find_first_bit - find the first set bit in a memory region |
599 | " jne 1f\n" | 666 | * @addr: The address to start the search at |
600 | " la %0,8(%0)\n" | 667 | * @size: The maximum size to search |
601 | " brct %2,0b\n" | 668 | * |
602 | " lgr %0,%3\n" | 669 | * Returns the bit-number of the first set bit, not the number of the byte |
603 | " j 5f\n" | 670 | * containing a bit. |
604 | "1: lg %2,0(%0,%4)\n" | 671 | */ |
605 | " sllg %0,%0,3\n" | 672 | static inline unsigned long find_first_bit(const unsigned long * addr, |
606 | " clr %2,%1\n" | 673 | unsigned long size) |
607 | " jne 2f\n" | ||
608 | " aghi %0,32\n" | ||
609 | " srlg %2,%2,32\n" | ||
610 | "2: lghi %1,0xff\n" | ||
611 | " tmll %2,0xffff\n" | ||
612 | " jno 3f\n" | ||
613 | " aghi %0,16\n" | ||
614 | " srl %2,16\n" | ||
615 | "3: tmll %2,0x00ff\n" | ||
616 | " jno 4f\n" | ||
617 | " aghi %0,8\n" | ||
618 | " srl %2,8\n" | ||
619 | "4: ngr %2,%1\n" | ||
620 | " ic %2,0(%2,%5)\n" | ||
621 | " algr %0,%2\n" | ||
622 | "5:" | ||
623 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
624 | : "a" (size), "a" (addr), "a" (&_zb_findmap), | ||
625 | "m" (*(addrtype *) addr) : "cc"); | ||
626 | return (res < size) ? res : size; | ||
627 | } | ||
628 | |||
629 | static inline unsigned long | ||
630 | find_first_bit(const unsigned long * addr, unsigned long size) | ||
631 | { | 674 | { |
632 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 675 | unsigned long bytes, bits; |
633 | unsigned long res, cmp, count; | ||
634 | 676 | ||
635 | if (!size) | 677 | if (!size) |
636 | return 0; | 678 | return 0; |
637 | asm volatile( | 679 | bytes = __ffs_word_loop(addr, size); |
638 | " slgr %1,%1\n" | 680 | bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes)); |
639 | " lgr %2,%3\n" | 681 | return (bits < size) ? bits : size; |
640 | " slgr %0,%0\n" | ||
641 | " aghi %2,63\n" | ||
642 | " srlg %2,%2,6\n" | ||
643 | "0: cg %1,0(%0,%4)\n" | ||
644 | " jne 1f\n" | ||
645 | " aghi %0,8\n" | ||
646 | " brct %2,0b\n" | ||
647 | " lgr %0,%3\n" | ||
648 | " j 5f\n" | ||
649 | "1: lg %2,0(%0,%4)\n" | ||
650 | " sllg %0,%0,3\n" | ||
651 | " clr %2,%1\n" | ||
652 | " jne 2f\n" | ||
653 | " aghi %0,32\n" | ||
654 | " srlg %2,%2,32\n" | ||
655 | "2: lghi %1,0xff\n" | ||
656 | " tmll %2,0xffff\n" | ||
657 | " jnz 3f\n" | ||
658 | " aghi %0,16\n" | ||
659 | " srl %2,16\n" | ||
660 | "3: tmll %2,0x00ff\n" | ||
661 | " jnz 4f\n" | ||
662 | " aghi %0,8\n" | ||
663 | " srl %2,8\n" | ||
664 | "4: ngr %2,%1\n" | ||
665 | " ic %2,0(%2,%5)\n" | ||
666 | " algr %0,%2\n" | ||
667 | "5:" | ||
668 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
669 | : "a" (size), "a" (addr), "a" (&_sb_findmap), | ||
670 | "m" (*(addrtype *) addr) : "cc"); | ||
671 | return (res < size) ? res : size; | ||
672 | } | 682 | } |
673 | 683 | ||
674 | #endif /* __s390x__ */ | 684 | /** |
675 | 685 | * find_next_zero_bit - find the first zero bit in a memory region | |
676 | static inline int | 686 | * @addr: The address to base the search on |
677 | find_next_zero_bit (const unsigned long * addr, unsigned long size, | 687 | * @offset: The bitnumber to start searching at |
678 | unsigned long offset) | 688 | * @size: The maximum size to search |
689 | */ | ||
690 | static inline int find_next_zero_bit (const unsigned long * addr, | ||
691 | unsigned long size, | ||
692 | unsigned long offset) | ||
679 | { | 693 | { |
680 | const unsigned long *p; | 694 | const unsigned long *p; |
681 | unsigned long bit, set; | 695 | unsigned long bit, set; |
@@ -688,10 +702,10 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, | |||
688 | p = addr + offset / __BITOPS_WORDSIZE; | 702 | p = addr + offset / __BITOPS_WORDSIZE; |
689 | if (bit) { | 703 | if (bit) { |
690 | /* | 704 | /* |
691 | * s390 version of ffz returns __BITOPS_WORDSIZE | 705 | * __ffz_word returns __BITOPS_WORDSIZE |
692 | * if no zero bit is present in the word. | 706 | * if no zero bit is present in the word. |
693 | */ | 707 | */ |
694 | set = ffz(*p >> bit) + bit; | 708 | set = __ffz_word(0, *p >> bit) + bit; |
695 | if (set >= size) | 709 | if (set >= size) |
696 | return size + offset; | 710 | return size + offset; |
697 | if (set < __BITOPS_WORDSIZE) | 711 | if (set < __BITOPS_WORDSIZE) |
@@ -703,9 +717,15 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size, | |||
703 | return offset + find_first_zero_bit(p, size); | 717 | return offset + find_first_zero_bit(p, size); |
704 | } | 718 | } |
705 | 719 | ||
706 | static inline int | 720 | /** |
707 | find_next_bit (const unsigned long * addr, unsigned long size, | 721 | * find_next_bit - find the first set bit in a memory region |
708 | unsigned long offset) | 722 | * @addr: The address to base the search on |
723 | * @offset: The bitnumber to start searching at | ||
724 | * @size: The maximum size to search | ||
725 | */ | ||
726 | static inline int find_next_bit (const unsigned long * addr, | ||
727 | unsigned long size, | ||
728 | unsigned long offset) | ||
709 | { | 729 | { |
710 | const unsigned long *p; | 730 | const unsigned long *p; |
711 | unsigned long bit, set; | 731 | unsigned long bit, set; |
@@ -718,10 +738,10 @@ find_next_bit (const unsigned long * addr, unsigned long size, | |||
718 | p = addr + offset / __BITOPS_WORDSIZE; | 738 | p = addr + offset / __BITOPS_WORDSIZE; |
719 | if (bit) { | 739 | if (bit) { |
720 | /* | 740 | /* |
721 | * s390 version of __ffs returns __BITOPS_WORDSIZE | 741 | * __ffs_word returns __BITOPS_WORDSIZE |
722 | * if no one bit is present in the word. | 742 | * if no one bit is present in the word. |
723 | */ | 743 | */ |
724 | set = __ffs(*p & (~0UL << bit)); | 744 | set = __ffs_word(0, *p & (~0UL << bit)); |
725 | if (set >= size) | 745 | if (set >= size) |
726 | return size + offset; | 746 | return size + offset; |
727 | if (set < __BITOPS_WORDSIZE) | 747 | if (set < __BITOPS_WORDSIZE) |
@@ -744,8 +764,6 @@ static inline int sched_find_first_bit(unsigned long *b) | |||
744 | return find_first_bit(b, 140); | 764 | return find_first_bit(b, 140); |
745 | } | 765 | } |
746 | 766 | ||
747 | #include <asm-generic/bitops/ffs.h> | ||
748 | |||
749 | #include <asm-generic/bitops/fls.h> | 767 | #include <asm-generic/bitops/fls.h> |
750 | #include <asm-generic/bitops/fls64.h> | 768 | #include <asm-generic/bitops/fls64.h> |
751 | 769 | ||
@@ -772,108 +790,23 @@ static inline int sched_find_first_bit(unsigned long *b) | |||
772 | test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) | 790 | test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) |
773 | #define ext2_test_bit(nr, addr) \ | 791 | #define ext2_test_bit(nr, addr) \ |
774 | test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) | 792 | test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr) |
775 | #define ext2_find_next_bit(addr, size, off) \ | ||
776 | generic_find_next_le_bit((unsigned long *)(addr), (size), (off)) | ||
777 | 793 | ||
778 | #ifndef __s390x__ | 794 | static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size) |
779 | |||
780 | static inline int | ||
781 | ext2_find_first_zero_bit(void *vaddr, unsigned int size) | ||
782 | { | 795 | { |
783 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | 796 | unsigned long bytes, bits; |
784 | unsigned long cmp, count; | ||
785 | unsigned int res; | ||
786 | 797 | ||
787 | if (!size) | 798 | if (!size) |
788 | return 0; | 799 | return 0; |
789 | asm volatile( | 800 | bytes = __ffz_word_loop(vaddr, size); |
790 | " lhi %1,-1\n" | 801 | bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes)); |
791 | " lr %2,%3\n" | 802 | return (bits < size) ? bits : size; |
792 | " ahi %2,31\n" | ||
793 | " srl %2,5\n" | ||
794 | " slr %0,%0\n" | ||
795 | "0: cl %1,0(%0,%4)\n" | ||
796 | " jne 1f\n" | ||
797 | " ahi %0,4\n" | ||
798 | " brct %2,0b\n" | ||
799 | " lr %0,%3\n" | ||
800 | " j 4f\n" | ||
801 | "1: l %2,0(%0,%4)\n" | ||
802 | " sll %0,3\n" | ||
803 | " ahi %0,24\n" | ||
804 | " lhi %1,0xff\n" | ||
805 | " tmh %2,0xffff\n" | ||
806 | " jo 2f\n" | ||
807 | " ahi %0,-16\n" | ||
808 | " srl %2,16\n" | ||
809 | "2: tml %2,0xff00\n" | ||
810 | " jo 3f\n" | ||
811 | " ahi %0,-8\n" | ||
812 | " srl %2,8\n" | ||
813 | "3: nr %2,%1\n" | ||
814 | " ic %2,0(%2,%5)\n" | ||
815 | " alr %0,%2\n" | ||
816 | "4:" | ||
817 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
818 | : "a" (size), "a" (vaddr), "a" (&_zb_findmap), | ||
819 | "m" (*(addrtype *) vaddr) : "cc"); | ||
820 | return (res < size) ? res : size; | ||
821 | } | 803 | } |
822 | 804 | ||
823 | #else /* __s390x__ */ | 805 | static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size, |
824 | 806 | unsigned long offset) | |
825 | static inline unsigned long | ||
826 | ext2_find_first_zero_bit(void *vaddr, unsigned long size) | ||
827 | { | ||
828 | typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype; | ||
829 | unsigned long res, cmp, count; | ||
830 | |||
831 | if (!size) | ||
832 | return 0; | ||
833 | asm volatile( | ||
834 | " lghi %1,-1\n" | ||
835 | " lgr %2,%3\n" | ||
836 | " aghi %2,63\n" | ||
837 | " srlg %2,%2,6\n" | ||
838 | " slgr %0,%0\n" | ||
839 | "0: clg %1,0(%0,%4)\n" | ||
840 | " jne 1f\n" | ||
841 | " aghi %0,8\n" | ||
842 | " brct %2,0b\n" | ||
843 | " lgr %0,%3\n" | ||
844 | " j 5f\n" | ||
845 | "1: cl %1,0(%0,%4)\n" | ||
846 | " jne 2f\n" | ||
847 | " aghi %0,4\n" | ||
848 | "2: l %2,0(%0,%4)\n" | ||
849 | " sllg %0,%0,3\n" | ||
850 | " aghi %0,24\n" | ||
851 | " lghi %1,0xff\n" | ||
852 | " tmlh %2,0xffff\n" | ||
853 | " jo 3f\n" | ||
854 | " aghi %0,-16\n" | ||
855 | " srl %2,16\n" | ||
856 | "3: tmll %2,0xff00\n" | ||
857 | " jo 4f\n" | ||
858 | " aghi %0,-8\n" | ||
859 | " srl %2,8\n" | ||
860 | "4: ngr %2,%1\n" | ||
861 | " ic %2,0(%2,%5)\n" | ||
862 | " algr %0,%2\n" | ||
863 | "5:" | ||
864 | : "=&a" (res), "=&d" (cmp), "=&a" (count) | ||
865 | : "a" (size), "a" (vaddr), "a" (&_zb_findmap), | ||
866 | "m" (*(addrtype *) vaddr) : "cc"); | ||
867 | return (res < size) ? res : size; | ||
868 | } | ||
869 | |||
870 | #endif /* __s390x__ */ | ||
871 | |||
872 | static inline int | ||
873 | ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) | ||
874 | { | 807 | { |
875 | unsigned long *addr = vaddr, *p; | 808 | unsigned long *addr = vaddr, *p; |
876 | unsigned long word, bit, set; | 809 | unsigned long bit, set; |
877 | 810 | ||
878 | if (offset >= size) | 811 | if (offset >= size) |
879 | return size; | 812 | return size; |
@@ -882,23 +815,11 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) | |||
882 | size -= offset; | 815 | size -= offset; |
883 | p = addr + offset / __BITOPS_WORDSIZE; | 816 | p = addr + offset / __BITOPS_WORDSIZE; |
884 | if (bit) { | 817 | if (bit) { |
885 | #ifndef __s390x__ | ||
886 | asm volatile( | ||
887 | " ic %0,0(%1)\n" | ||
888 | " icm %0,2,1(%1)\n" | ||
889 | " icm %0,4,2(%1)\n" | ||
890 | " icm %0,8,3(%1)" | ||
891 | : "=&a" (word) : "a" (p), "m" (*p) : "cc"); | ||
892 | #else | ||
893 | asm volatile( | ||
894 | " lrvg %0,%1" | ||
895 | : "=a" (word) : "m" (*p) ); | ||
896 | #endif | ||
897 | /* | 818 | /* |
898 | * s390 version of ffz returns __BITOPS_WORDSIZE | 819 | * s390 version of ffz returns __BITOPS_WORDSIZE |
899 | * if no zero bit is present in the word. | 820 | * if no zero bit is present in the word. |
900 | */ | 821 | */ |
901 | set = ffz(word >> bit) + bit; | 822 | set = ffz(__load_ulong_le(p, 0) >> bit) + bit; |
902 | if (set >= size) | 823 | if (set >= size) |
903 | return size + offset; | 824 | return size + offset; |
904 | if (set < __BITOPS_WORDSIZE) | 825 | if (set < __BITOPS_WORDSIZE) |
@@ -910,6 +831,47 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset) | |||
910 | return offset + ext2_find_first_zero_bit(p, size); | 831 | return offset + ext2_find_first_zero_bit(p, size); |
911 | } | 832 | } |
912 | 833 | ||
834 | static inline unsigned long ext2_find_first_bit(void *vaddr, | ||
835 | unsigned long size) | ||
836 | { | ||
837 | unsigned long bytes, bits; | ||
838 | |||
839 | if (!size) | ||
840 | return 0; | ||
841 | bytes = __ffs_word_loop(vaddr, size); | ||
842 | bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes)); | ||
843 | return (bits < size) ? bits : size; | ||
844 | } | ||
845 | |||
846 | static inline int ext2_find_next_bit(void *vaddr, unsigned long size, | ||
847 | unsigned long offset) | ||
848 | { | ||
849 | unsigned long *addr = vaddr, *p; | ||
850 | unsigned long bit, set; | ||
851 | |||
852 | if (offset >= size) | ||
853 | return size; | ||
854 | bit = offset & (__BITOPS_WORDSIZE - 1); | ||
855 | offset -= bit; | ||
856 | size -= offset; | ||
857 | p = addr + offset / __BITOPS_WORDSIZE; | ||
858 | if (bit) { | ||
859 | /* | ||
860 | * s390 version of ffz returns __BITOPS_WORDSIZE | ||
861 | * if no zero bit is present in the word. | ||
862 | */ | ||
863 | set = ffs(__load_ulong_le(p, 0) >> bit) + bit; | ||
864 | if (set >= size) | ||
865 | return size + offset; | ||
866 | if (set < __BITOPS_WORDSIZE) | ||
867 | return set + offset; | ||
868 | offset += __BITOPS_WORDSIZE; | ||
869 | size -= __BITOPS_WORDSIZE; | ||
870 | p++; | ||
871 | } | ||
872 | return offset + ext2_find_first_bit(p, size); | ||
873 | } | ||
874 | |||
913 | #include <asm-generic/bitops/minix.h> | 875 | #include <asm-generic/bitops/minix.h> |
914 | 876 | ||
915 | #endif /* __KERNEL__ */ | 877 | #endif /* __KERNEL__ */ |
diff --git a/include/asm-s390/cacheflush.h b/include/asm-s390/cacheflush.h index f7cade8083f3..49d5af916d01 100644 --- a/include/asm-s390/cacheflush.h +++ b/include/asm-s390/cacheflush.h | |||
@@ -24,4 +24,8 @@ | |||
24 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | 24 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ |
25 | memcpy(dst, src, len) | 25 | memcpy(dst, src, len) |
26 | 26 | ||
27 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
28 | void kernel_map_pages(struct page *page, int numpages, int enable); | ||
29 | #endif | ||
30 | |||
27 | #endif /* _S390_CACHEFLUSH_H */ | 31 | #endif /* _S390_CACHEFLUSH_H */ |
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h index 7109c7cab87e..289053ef5e60 100644 --- a/include/asm-s390/ccwgroup.h +++ b/include/asm-s390/ccwgroup.h | |||
@@ -37,6 +37,7 @@ struct ccwgroup_device { | |||
37 | * @remove: function called on remove | 37 | * @remove: function called on remove |
38 | * @set_online: function called when device is set online | 38 | * @set_online: function called when device is set online |
39 | * @set_offline: function called when device is set offline | 39 | * @set_offline: function called when device is set offline |
40 | * @shutdown: function called when device is shut down | ||
40 | * @driver: embedded driver structure | 41 | * @driver: embedded driver structure |
41 | */ | 42 | */ |
42 | struct ccwgroup_driver { | 43 | struct ccwgroup_driver { |
@@ -49,6 +50,7 @@ struct ccwgroup_driver { | |||
49 | void (*remove) (struct ccwgroup_device *); | 50 | void (*remove) (struct ccwgroup_device *); |
50 | int (*set_online) (struct ccwgroup_device *); | 51 | int (*set_online) (struct ccwgroup_device *); |
51 | int (*set_offline) (struct ccwgroup_device *); | 52 | int (*set_offline) (struct ccwgroup_device *); |
53 | void (*shutdown)(struct ccwgroup_device *); | ||
52 | 54 | ||
53 | struct device_driver driver; | 55 | struct device_driver driver; |
54 | }; | 56 | }; |
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 79b9eab1a0c7..3f520754e71c 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h | |||
@@ -115,15 +115,21 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
115 | #ifndef __s390x__ | 115 | #ifndef __s390x__ |
116 | #define VMALLOC_START 0x78000000UL | 116 | #define VMALLOC_START 0x78000000UL |
117 | #define VMALLOC_END 0x7e000000UL | 117 | #define VMALLOC_END 0x7e000000UL |
118 | #define VMEM_MAP_MAX 0x80000000UL | 118 | #define VMEM_MAP_END 0x80000000UL |
119 | #else /* __s390x__ */ | 119 | #else /* __s390x__ */ |
120 | #define VMALLOC_START 0x3e000000000UL | 120 | #define VMALLOC_START 0x3e000000000UL |
121 | #define VMALLOC_END 0x3e040000000UL | 121 | #define VMALLOC_END 0x3e040000000UL |
122 | #define VMEM_MAP_MAX 0x40000000000UL | 122 | #define VMEM_MAP_END 0x40000000000UL |
123 | #endif /* __s390x__ */ | 123 | #endif /* __s390x__ */ |
124 | 124 | ||
125 | /* | ||
126 | * VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1 | ||
127 | * mapping. This needs to be calculated at compile time since the size of the | ||
128 | * VMEM_MAP is static but the size of struct page can change. | ||
129 | */ | ||
130 | #define VMEM_MAX_PHYS min(VMALLOC_START, ((VMEM_MAP_END - VMALLOC_END) / \ | ||
131 | sizeof(struct page) * PAGE_SIZE) & ~((16 << 20) - 1)) | ||
125 | #define VMEM_MAP ((struct page *) VMALLOC_END) | 132 | #define VMEM_MAP ((struct page *) VMALLOC_END) |
126 | #define VMEM_MAP_SIZE ((VMALLOC_START / PAGE_SIZE) * sizeof(struct page)) | ||
127 | 133 | ||
128 | /* | 134 | /* |
129 | * A 31 bit pagetable entry of S390 has following format: | 135 | * A 31 bit pagetable entry of S390 has following format: |