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: |
