Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Feb 2015 01:42:32 +0000 (17:42 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Feb 2015 01:42:32 +0000 (17:42 -0800)
Pull s390 updates from Martin Schwidefsky:

 - The remaining patches for the z13 machine support: kernel build
   option for z13, the cache synonym avoidance, SMT support,
   compare-and-delay for spinloops and the CES5S crypto adapater.

 - The ftrace support for function tracing with the gcc hotpatch option.
   This touches common code Makefiles, Steven is ok with the changes.

 - The hypfs file system gets an extension to access diagnose 0x0c data
   in user space for performance analysis for Linux running under z/VM.

 - The iucv hvc console gets wildcard spport for the user id filtering.

 - The cacheinfo code is converted to use the generic infrastructure.

 - Cleanup and bug fixes.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (42 commits)
  s390/process: free vx save area when releasing tasks
  s390/hypfs: Eliminate hypfs interval
  s390/hypfs: Add diagnose 0c support
  s390/cacheinfo: don't use smp_processor_id() in preemptible context
  s390/zcrypt: fixed domain scanning problem (again)
  s390/smp: increase maximum value of NR_CPUS to 512
  s390/jump label: use different nop instruction
  s390/jump label: add sanity checks
  s390/mm: correct missing space when reporting user process faults
  s390/dasd: cleanup profiling
  s390/dasd: add locking for global_profile access
  s390/ftrace: hotpatch support for function tracing
  ftrace: let notrace function attribute disable hotpatching if necessary
  ftrace: allow architectures to specify ftrace compile options
  s390: reintroduce diag 44 calls for cpu_relax()
  s390/zcrypt: Add support for new crypto express (CEX5S) adapter.
  s390/zcrypt: Number of supported ap domains is not retrievable.
  s390/spinlock: add compare-and-delay to lock wait loops
  s390/tape: remove redundant if statement
  s390/hvc_iucv: add simple wildcard matches to the iucv allow filter
  ...

82 files changed:
Documentation/s390/Debugging390.txt
Makefile
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/configs/default_defconfig
arch/s390/configs/gcov_defconfig
arch/s390/configs/performance_defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/crypto/aes_s390.c
arch/s390/defconfig
arch/s390/hypfs/Makefile
arch/s390/hypfs/hypfs.h
arch/s390/hypfs/hypfs_dbfs.c
arch/s390/hypfs/hypfs_diag0c.c [new file with mode: 0644]
arch/s390/hypfs/inode.c
arch/s390/include/asm/cpu_mf.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/jump_label.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/reset.h
arch/s390/include/asm/sclp.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/sigp.h
arch/s390/include/asm/smp.h
arch/s390/include/asm/sysinfo.h
arch/s390/include/asm/topology.h
arch/s390/include/uapi/asm/hypfs.h
arch/s390/kernel/Makefile
arch/s390/kernel/base.S
arch/s390/kernel/cache.c
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/head.S
arch/s390/kernel/ipl.c
arch/s390/kernel/jump_label.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/mcount.S
arch/s390/kernel/process.c
arch/s390/kernel/processor.c
arch/s390/kernel/sclp.S
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/sysinfo.c
arch/s390/kernel/topology.c
arch/s390/kernel/vtime.c
arch/s390/lib/spinlock.c
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/s390/mm/mmap.c
arch/s390/mm/pgtable.c
arch/s390/pci/pci_mmio.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_proc.c
drivers/s390/block/dcssblk.c
drivers/s390/char/hmcdrv_ftp.c
drivers/s390/char/hmcdrv_mod.c
drivers/s390/char/sclp_early.c
drivers/s390/char/tape_34xx.c
drivers/s390/cio/cio.c
drivers/s390/cio/idset.c
drivers/s390/cio/idset.h
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_cex4.c
drivers/tty/hvc/hvc_iucv.c
include/linux/compiler.h
kernel/Makefile
kernel/events/Makefile
kernel/locking/Makefile
kernel/sched/Makefile
kernel/trace/Makefile
lib/Makefile
scripts/Makefile.build
scripts/recordmcount.pl

index 08911b5c6b0e430ed82ff569f9571cbc160edfd3..3df8babcdc41ed7079e59138e6dafb07f03407a0 100644 (file)
@@ -1,14 +1,14 @@
-              
-                          Debugging on Linux for s/390 & z/Architecture
-                                      by
-               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
-               Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
-                              Best viewed with fixed width fonts 
+
+                 Debugging on Linux for s/390 & z/Architecture
+                                      by
+         Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+    Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+                       Best viewed with fixed width fonts
 
 Overview of Document:
 =====================
-This document is intended to give a good overview of how to debug
-Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a
+This document is intended to give a good overview of how to debug Linux for
+s/390 and z/Architecture. It is not intended as a complete reference and not a
 tutorial on the fundamentals of C & assembly. It doesn't go into
 390 IO in any detail. It is intended to complement the documents in the
 reference section below & any other worthwhile references you get.
@@ -35,7 +35,6 @@ Examining core dumps
 ldd
 Debugging modules
 The proc file system
-Starting points for debugging scripting languages etc.
 SysRq
 References
 Special Thanks
@@ -44,18 +43,20 @@ Register Set
 ============
 The current architectures have the following registers.
  
-16  General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
-
-16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory management,
-interrupt control,debugging control etc.
-
-16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture
-not used by normal programs but potentially could 
-be used as temporary storage. Their main purpose is their 1 to 1
-association with general purpose registers and are used in
-the kernel for copying data between kernel & user address spaces.
-Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit 
-pointer ) ) is currently used by the pthread library as a pointer to
+16 General propose registers, 32 bit on s/390 and 64 bit on z/Architecture,
+r0-r15 (or gpr0-gpr15), used for arithmetic and addressing.
+
+16 Control registers, 32 bit on s/390 and 64 bit on z/Architecture, cr0-cr15,
+kernel usage only, used for memory management, interrupt control, debugging
+control etc.
+
+16 Access registers (ar0-ar15), 32 bit on both s/390 and z/Architecture,
+normally not used by normal programs but potentially could be used as
+temporary storage. These registers have a 1:1 association with general
+purpose registers and are designed to be used in the so-called access
+register mode to select different address spaces.
+Access register 0 (and access register 1 on z/Architecture, which needs a
+64 bit pointer) is currently used by the pthread library as a pointer to
 the current running threads private area.
 
 16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating 
@@ -90,18 +91,19 @@ s/390 z/Architecture
 
 6       6     Input/Output interrupt Mask
 
-7       7     External interrupt Mask used primarily for interprocessor signalling & 
-             clock interrupts.
+7      7     External interrupt Mask used primarily for interprocessor
+             signalling and clock interrupts.
 
-8-11  8-11    PSW Key used for complex memory protection mechanism not used under linux
+8-11  8-11    PSW Key used for complex memory protection mechanism
+             (not used under linux)
 
 12      12    1 on s/390 0 on z/Architecture
 
 13      13    Machine Check Mask 1=enable machine check interrupts
 
-14      14    Wait State set this to 1 to stop the processor except for interrupts & give 
-             time to other LPARS used in CPU idle in the kernel to increase overall 
-             usage of processor resources.
+14     14    Wait State. Set this to 1 to stop the processor except for
+             interrupts and give  time to other LPARS. Used in CPU idle in
+             the kernel to increase overall usage of processor resources.
 
 15      15    Problem state ( if set to 1 certain instructions are disabled )
              all linux user programs run with this bit 1 
@@ -165,21 +167,23 @@ s/390 z/Architecture
               when loading the address with LPSWE otherwise a 
                specification exception occurs, LPSW is fully backward
                compatible.
-         
-         
+
+
 Prefix Page(s)
---------------   
+--------------
 This per cpu memory area is too intimately tied to the processor not to mention.
-It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged 
-with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set 
-prefix instruction in linux'es startup. 
-This page is mapped to a different prefix for each processor in an SMP configuration
-( assuming the os designer is sane of course :-) ).
-Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture 
-are used by the processor itself for holding such information as exception indications & 
-entry points for exceptions.
-Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture 
-( there is a gap on z/Architecture too currently between 0xc00 & 1000 which linux uses ).
+It exists between the real addresses 0-4096 on s/390 and between 0-8192 on
+z/Architecture and is exchanged with one page on s/390 or two pages on
+z/Architecture in absolute storage by the set prefix instruction during Linux
+startup.
+This page is mapped to a different prefix for each processor in an SMP
+configuration (assuming the OS designer is sane of course).
+Bytes 0-512 (200 hex) on s/390 and 0-512, 4096-4544, 4604-5119 currently on
+z/Architecture are used by the processor itself for holding such information
+as exception indications and entry points for exceptions.
+Bytes after 0xc00 hex are used by linux for per processor globals on s/390 and
+z/Architecture (there is a gap on z/Architecture currently between 0xc00 and
+0x1000, too, which is used by Linux).
 The closest thing to this on traditional architectures is the interrupt
 vector table. This is a good thing & does simplify some of the kernel coding
 however it means that we now cannot catch stray NULL pointers in the
@@ -192,26 +196,26 @@ Address Spaces on Intel Linux
 
 The traditional Intel Linux is approximately mapped as follows forgive
 the ascii art.
-0xFFFFFFFF 4GB Himem                        *****************
-                                            *               *
-                                            * Kernel Space  *
-                                            *               *
-                                            *****************          ****************
-User Space Himem (typically 0xC0000000 3GB )*  User Stack   *          *              *
-                                           *****************          *              *
-                                           *  Shared Libs  *          * Next Process *          
-                                            *****************          *     to       *  
-                                           *               *    <==   *     Run      *  <==
-                                           *  User Program *          *              *
-                                           *   Data BSS    *          *              *
-                                            *   Text       *          *              *
-                                           *   Sections    *          *              *
-0x00000000                                 *****************          ****************
-
-Now it is easy to see that on Intel it is quite easy to recognise a kernel address 
-as being one greater than user space himem ( in this case 0xC0000000).
-& addresses of less than this are the ones in the current running program on this
-processor ( if an smp box ).
+0xFFFFFFFF 4GB Himem           *****************
+                               *               *
+                               * Kernel Space  *
+                               *               *
+                               *****************         ****************
+User Space Himem               *  User Stack   *         *              *
+(typically 0xC0000000 3GB )    *****************         *              *
+                               *  Shared Libs  *         * Next Process *
+                               *****************         *     to       *
+                               *               *   <==   *     Run      *  <==
+                               *  User Program *         *              *
+                               *   Data BSS    *         *              *
+                               *    Text       *         *              *
+                               *   Sections    *         *              *
+0x00000000                     *****************         ****************
+
+Now it is easy to see that on Intel it is quite easy to recognise a kernel
+address as being one greater than user space himem (in this case 0xC0000000),
+and addresses of less than this are the ones in the current running program on
+this processor (if an smp box).
 If using the virtual machine ( VM ) as a debugger it is quite difficult to
 know which user process is running as the address space you are looking at
 could be from any process in the run queue.
@@ -247,8 +251,8 @@ Our addressing scheme is basically as follows:
 Himem 0x7fffffff 2GB on s/390    *****************          ****************
 currently 0x3ffffffffff (2^42)-1 *  User Stack   *          *              *
 on z/Architecture.              *****************          *              *
-                                *  Shared Libs  *          *              *      
-                                 *****************          *              *  
+                                *  Shared Libs  *          *              *
+                                *****************          *              *
                                 *               *          *    Kernel    *  
                                 *  User Program *          *              *
                                 *   Data BSS    *          *              *
@@ -301,10 +305,10 @@ Virtual Addresses on s/390 & z/Architecture
 ===========================================
 
 A virtual address on s/390 is made up of 3 parts
-The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology ) 
-being bits 1-11.
-The PX ( page index, corresponding to the page table entry (pte) in linux terminology )
-being bits 12-19. 
+The SX (segment index, roughly corresponding to the PGD & PMD in Linux
+terminology) being bits 1-11.
+The PX (page index, corresponding to the page table entry (pte) in Linux
+terminology) being bits 12-19.
 The remaining bits BX (the byte index are the offset in the page )
 i.e. bits 20 to 31.
 
@@ -368,9 +372,9 @@ each processor as follows.
             *        ( 8K )        *
 16K aligned ************************ 
 
-What this means is that we don't need to dedicate any register or global variable
-to point to the current running process & can retrieve it with the following
-very simple construct for s/390 & one very similar for z/Architecture.
+What this means is that we don't need to dedicate any register or global
+variable to point to the current running process & can retrieve it with the
+following very simple construct for s/390 & one very similar for z/Architecture.
 
 static inline struct task_struct * get_current(void)
 {
@@ -403,8 +407,8 @@ Note: To follow stackframes requires a knowledge of C or Pascal &
 limited knowledge of one assembly language.
 
 It should be noted that there are some differences between the
-s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have
-to maintain compatibility with older linkage formats.
+s/390 and z/Architecture stack layouts as the z/Architecture stack layout
+didn't have to maintain compatibility with older linkage formats.
 
 Glossary:
 ---------
@@ -440,7 +444,7 @@ The code generated by the compiler to return to the caller.
 
 frameless-function
 A frameless function in Linux for s390 & z/Architecture is one which doesn't 
-need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture )
+need more than the register save area (96 bytes on s/390, 160 on z/Architecture)
 given to it by the caller.
 A frameless function never:
 1) Sets up a back chain.
@@ -588,8 +592,8 @@ A sample program with comments.
 
 Comments on the function test
 -----------------------------
-1) It didn't need to set up a pointer to the constant pool gpr13 as it isn't used
-( :-( ).
+1) It didn't need to set up a pointer to the constant pool gpr13 as it is not
+used ( :-( ).
 2) This is a frameless function & no stack is bought.
 3) The compiler was clever enough to recognise that it could return the
 value in r2 as well as use it for the passed in parameter ( :-) ).
@@ -743,35 +747,34 @@ Debugging under VM
 Notes
 -----
 Addresses & values in the VM debugger are always hex never decimal
-Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2> 
-e.g. The address range  0x2000 to 0x3000 can be described as 2000-3000 or 2000.1000
+Address ranges are of the format <HexValue1>-<HexValue2> or
+<HexValue1>.<HexValue2>
+For example, the address range 0x2000 to 0x3000 can be described as 2000-3000
+or 2000.1000
 
 The VM Debugger is case insensitive.
 
-VM's strengths are usually other debuggers weaknesses you can get at any resource
-no matter how sensitive e.g. memory management resources,change address translation
-in the PSW. For kernel hacking you will reap dividends if you get good at it.
-
-The VM Debugger displays operators but not operands, probably because some
-of it was written when memory was expensive & the programmer was probably proud that
-it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by
-changing the interface :-), also the debugger displays useful information on the same line & 
-the author of the code probably felt that it was a good idea not to go over 
-the 80 columns on the screen. 
-
-As some of you are probably in a panic now this isn't as unintuitive as it may seem
-as the 390 instructions are easy to decode mentally & you can make a good guess at a lot 
-of them as all the operands are nibble ( half byte aligned ) & if you have an objdump listing
-also it is quite easy to follow, if you don't have an objdump listing keep a copy of
-the s/390 Reference Summary & look at between pages 2 & 7 or alternatively the
-s/390 principles of operation.
+VM's strengths are usually other debuggers weaknesses you can get at any
+resource no matter how sensitive e.g. memory management resources, change
+address translation in the PSW. For kernel hacking you will reap dividends if
+you get good at it.
+
+The VM Debugger displays operators but not operands, and also the debugger
+displays useful information on the same line as the author of the code probably
+felt that it was a good idea not to go over the 80 columns on the screen.
+This isn't as unintuitive as it may seem as the s/390 instructions are easy to
+decode mentally and you can make a good guess at a lot of them as all the
+operands are nibble (half byte aligned).
+So if you have an objdump listing by hand, it is quite easy to follow, and if
+you don't have an objdump listing keep a copy of the s/390 Reference Summary
+or alternatively the s/390 principles of operation next to you.
 e.g. even I can guess that 
 0001AFF8' LR    180F        CC 0
 is a ( load register ) lr r0,r15 
 
-Also it is very easy to tell the length of a 390 instruction from the 2 most significant
-bits in the instruction ( not that this info is really useful except if you are trying to
-make sense of a hexdump of code ).
+Also it is very easy to tell the length of a 390 instruction from the 2 most
+significant bits in the instruction (not that this info is really useful except
+if you are trying to make sense of a hexdump of code).
 Here is a table
 Bits                    Instruction Length
 ------------------------------------------
@@ -780,9 +783,6 @@ Bits                    Instruction Length
 10                          4 Bytes
 11                          6 Bytes
 
-
-
-
 The debugger also displays other useful info on the same line such as the
 addresses being operated on destination addresses of branches & condition codes.
 e.g.  
@@ -853,8 +853,8 @@ Displaying & modifying Registers
 --------------------------------
 D G will display all the gprs
 Adding a extra G to all the commands is necessary to access the full 64 bit 
-content in VM on z/Architecture obviously this isn't required for access registers
-as these are still 32 bit.
+content in VM on z/Architecture. Obviously this isn't required for access
+registers as these are still 32 bit.
 e.g. DGG instead of DG 
 D X will display all the control registers
 D AR will display all the access registers
@@ -870,10 +870,11 @@ Displaying Memory
 -----------------
 To display memory mapped using the current PSW's mapping try
 D <range>
-To make VM display a message each time it hits a particular address & continue try
+To make VM display a message each time it hits a particular address and
+continue try
 D I<range> will disassemble/display a range of instructions.
 ST addr 32 bit word will store a 32 bit aligned address
-D T<range> will display the EBCDIC in an address ( if you are that way inclined )
+D T<range> will display the EBCDIC in an address (if you are that way inclined)
 D R<range> will display real addresses ( without DAT ) but with prefixing.
 There are other complex options to display if you need to get at say home space
 but are in primary space the easiest thing to do is to temporarily
@@ -884,8 +885,8 @@ restore it.
  
 Hints
 -----
-If you want to issue a debugger command without halting your virtual machine with the
-PA1 key try prefixing the command with #CP e.g.
+If you want to issue a debugger command without halting your virtual machine
+with the PA1 key try prefixing the command with #CP e.g.
 #cp tr i pswa 2000
 also suffixing most debugger commands with RUN will cause them not
 to stop just display the mnemonic at the current instruction on the console.
@@ -903,9 +904,10 @@ This sends a message to your own console each time do_signal is entered.
 script with breakpoints on every kernel procedure, this isn't a good idea
 because there are thousands of these routines & VM can only set 255 breakpoints
 at a time so you nearly had to spend as long pruning the file down as you would 
-entering the msg's by hand ),however, the trick might be useful for a single object file.
-On linux'es 3270 emulator x3270 there is a very useful option under the file ment
-Save Screens In File this is very good of keeping a copy of traces. 
+entering the msgs by hand), however, the trick might be useful for a single
+object file. In the 3270 terminal emulator x3270 there is a very useful option
+in the file menu called "Save Screen In File" - this is very good for keeping a
+copy of traces.
 
 From CMS help <command name> will give you online help on a particular command. 
 e.g. 
@@ -920,7 +922,8 @@ SET PF9 IMM B
 This does a single step in VM on pressing F8. 
 SET PF10  ^
 This sets up the ^ key.
-which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly into some 3270 consoles.
+which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly
+into some 3270 consoles.
 SET PF11 ^-
 This types the starting keystrokes for a sysrq see SysRq below.
 SET PF12 RETRIEVE
@@ -1014,8 +1017,8 @@ Tracing Program Exceptions
 --------------------------
 If you get a crash which says something like
 illegal operation or specification exception followed by a register dump
-You can restart linux & trace these using the tr prog <range or value> trace option.
-
+You can restart linux & trace these using the tr prog <range or value> trace
+option.
 
 
 The most common ones you will normally be tracing for is
@@ -1057,9 +1060,10 @@ TR GOTO INITIAL
 
 Tracing linux syscalls under VM
 -------------------------------
-Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 
-possibilities of these as the instruction is made up of a  0xA opcode & the second byte being
-the syscall number. They are traced using the simple command.
+Syscalls are implemented on Linux for S390 by the Supervisor call instruction
+(SVC). There 256 possibilities of these as the instruction is made up of a 0xA
+opcode and the second byte being the syscall number. They are traced using the
+simple command:
 TR SVC  <Optional value or range>
 the syscalls are defined in linux/arch/s390/include/asm/unistd.h
 e.g. to trace all file opens just do
@@ -1070,12 +1074,12 @@ SMP Specific commands
 ---------------------
 To find out how many cpus you have
 Q CPUS displays all the CPU's available to your virtual machine
-To find the cpu that the current cpu VM debugger commands are being directed at do
-Q CPU to change the current cpu VM debugger commands are being directed at do
+To find the cpu that the current cpu VM debugger commands are being directed at
+do Q CPU to change the current cpu VM debugger commands are being directed at do
 CPU <desired cpu no>
 
-On a SMP guest issue a command to all CPUs try prefixing the command with cpu all.
-To issue a command to a particular cpu try cpu <cpu number> e.g.
+On a SMP guest issue a command to all CPUs try prefixing the command with cpu
+all. To issue a command to a particular cpu try cpu <cpu number> e.g.
 CPU 01 TR I R 2000.3000
 If you are running on a guest with several cpus & you have a IO related problem
 & cannot follow the flow of code but you know it isn't smp related.
@@ -1101,10 +1105,10 @@ D TX0.100
 
 Alternatively
 =============
-Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which
-will convert a command line of hex digits to ascii text which can be compiled under linux & 
-you can copy the hex digits from your x3270 terminal to your xterm if you are debugging
-from a linuxbox.
+Under older VM debuggers (I love EBDIC too) you can use following little
+program which converts a command line of hex digits to ascii text. It can be
+compiled under linux and you can copy the hex digits from your x3270 terminal
+to your xterm if you are debugging from a linuxbox.
 
 This is quite useful when looking at a parameter passed in as a text string
 under VM ( unless you are good at decoding ASCII in your head ).
@@ -1114,14 +1118,14 @@ TR SVC 5
 We have stopped at a breakpoint
 000151B0' SVC   0A05     -> 0001909A'   CC 0
 
-D 20.8 to check the SVC old psw in the prefix area & see was it from userspace
-( for the layout of the prefix area consult P18 of the s/390 390 Reference Summary 
-if you have it available ).
+D 20.8 to check the SVC old psw in the prefix area and see was it from userspace
+(for the layout of the prefix area consult the "Fixed Storage Locations"
+chapter of the s/390 Reference Summary if you have it available).
 V00000020  070C2000 800151B2
 The problem state bit wasn't set &  it's also too early in the boot sequence
 for it to be a userspace SVC if it was we would have to temporarily switch the 
-psw to user space addressing so we could get at the first parameter of the open in
-gpr2.
+psw to user space addressing so we could get at the first parameter of the open
+in gpr2.
 Next do a 
 D G2
 GPR  2 =  00014CB4
@@ -1208,9 +1212,9 @@ Here are the tricks I use 9 out of 10 times it works pretty well,
 
 When your backchain reaches a dead end
 --------------------------------------
-This can happen when an exception happens in the kernel & the kernel is entered twice
-if you reach the NULL pointer at the end of the back chain you should be
-able to sniff further back if you follow the following tricks.
+This can happen when an exception happens in the kernel and the kernel is
+entered twice. If you reach the NULL pointer at the end of the back chain you
+should be able to sniff further back if you follow the following tricks.
 1) A kernel address should be easy to recognise since it is in
 primary space & the problem state bit isn't set & also
 The Hi bit of the address is set.
@@ -1260,8 +1264,8 @@ V000FFFD0  00010400 80010802 8001085A 000FFFA0
 
 our 3rd return address is 8001085A
 
-as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines
-for the sake of optimisation don't set up a backchain.
+as the 04B52002 looks suspiciously like rubbish it is fair to assume that the
+kernel entry routines for the sake of optimisation don't set up a backchain.
 
 now look at System.map to see if the addresses make any sense.
 
@@ -1289,67 +1293,75 @@ Congrats you've done your first backchain.
 s/390 & z/Architecture IO Overview
 ==================================
 
-I am not going to give a course in 390 IO architecture as this would take me quite a
-while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have 
-the s/390 principles of operation available read this instead. If nothing else you may find a few 
-useful keywords in here & be able to use them on a web search engine like altavista to find 
-more useful information.
+I am not going to give a course in 390 IO architecture as this would take me
+quite a while and I'm no expert. Instead I'll give a 390 IO architecture
+summary for Dummies. If you have the s/390 principles of operation available
+read this instead. If nothing else you may find a few useful keywords in here
+and be able to use them on a web search engine to find more useful information.
 
 Unlike other bus architectures modern 390 systems do their IO using mostly
-fibre optics & devices such as tapes & disks can be shared between several mainframes,
-also S390 can support up to 65536 devices while a high end PC based system might be choking
-with around 64. Here is some of the common IO terminology
+fibre optics and devices such as tapes and disks can be shared between several
+mainframes. Also S390 can support up to 65536 devices while a high end PC based
+system might be choking with around 64.
 
-Subchannel:
-This is the logical number most IO commands use to talk to an IO device there can be up to
-0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM
-for simplicity they are allocated contiguously, however on the native hardware they are not
-they typically stay consistent between boots provided no new hardware is inserted or removed.
-Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL,
-HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & 
-TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most
-important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check
-whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel
-can have up to 8 channel paths to a device this offers redundancy if one is not available.
+Here is some of the common IO terminology:
 
+Subchannel:
+This is the logical number most IO commands use to talk to an IO device. There
+can be up to 0x10000 (65536) of these in a configuration, typically there are a
+few hundred. Under VM for simplicity they are allocated contiguously, however
+on the native hardware they are not. They typically stay consistent between
+boots provided no new hardware is inserted or removed.
+Under Linux for s390 we use these as IRQ's and also when issuing an IO command
+(CLEAR SUBCHANNEL, HALT SUBCHANNEL, MODIFY SUBCHANNEL, RESUME SUBCHANNEL,
+START SUBCHANNEL, STORE SUBCHANNEL and TEST SUBCHANNEL). We use this as the ID
+of the device we wish to talk to. The most important of these instructions are
+START SUBCHANNEL (to start IO), TEST SUBCHANNEL (to check whether the IO
+completed successfully) and HALT SUBCHANNEL (to kill IO). A subchannel can have
+up to 8 channel paths to a device, this offers redundancy if one is not
+available.
 
 Device Number:
-This number remains static & Is closely tied to the hardware, there are 65536 of these
-also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) 
-& another lsb 8 bits. These remain static even if more devices are inserted or removed
-from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided
-devices aren't inserted or removed.
+This number remains static and is closely tied to the hardware. There are 65536
+of these, made up of a CHPID (Channel Path ID, the most significant 8 bits) and
+another lsb 8 bits. These remain static even if more devices are inserted or
+removed from the hardware. There is a 1 to 1 mapping between subchannels and
+device numbers, provided devices aren't inserted or removed.
 
 Channel Control Words:
-CCWS are linked lists of instructions initially pointed to by an operation request block (ORB),
-which is initially given to Start Subchannel (SSCH) command along with the subchannel number
-for the IO subsystem to process while the CPU continues executing normal code.
-These come in two flavours, Format 0 ( 24 bit for backward )
-compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write 
-( & many other instructions ) they consist of a length field & an absolute address field.
-For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the
-channel is idle & the second for device end ( secondary status ) sometimes you get both
-concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each interrupt,
-from which you receive an Interruption response block (IRB). If you get channel & device end 
-status in the IRB without channel checks etc. your IO probably went okay. If you didn't you
-probably need a doctor to examine the IRB & extended status word etc.
+CCWs are linked lists of instructions initially pointed to by an operation
+request block (ORB), which is initially given to Start Subchannel (SSCH)
+command along with the subchannel number for the IO subsystem to process
+while the CPU continues executing normal code.
+CCWs come in two flavours, Format 0 (24 bit for backward compatibility) and
+Format 1 (31 bit). These are typically used to issue read and write (and many
+other) instructions. They consist of a length field and an absolute address
+field.
+Each IO typically gets 1 or 2 interrupts, one for channel end (primary status)
+when the channel is idle, and the second for device end (secondary status).
+Sometimes you get both concurrently. You check how the IO went on by issuing a
+TEST SUBCHANNEL at each interrupt, from which you receive an Interruption
+response block (IRB). If you get channel and device end status in the IRB
+without channel checks etc. your IO probably went okay. If you didn't you
+probably need to examine the IRB, extended status word etc.
 If an error occurs, more sophisticated control units have a facility known as
-concurrent sense this means that if an error occurs Extended sense information will
-be presented in the Extended status word in the IRB if not you have to issue a
-subsequent SENSE CCW command after the test subchannel. 
+concurrent sense. This means that if an error occurs Extended sense information
+will be presented in the Extended status word in the IRB. If not you have to
+issue a subsequent SENSE CCW command after the test subchannel.
 
 
-TPI( Test pending interrupt) can also be used for polled IO but in multitasking multiprocessor
-systems it isn't recommended except for checking special cases ( i.e. non looping checks for
-pending IO etc. ).
+TPI (Test pending interrupt) can also be used for polled IO, but in
+multitasking multiprocessor systems it isn't recommended except for
+checking special cases (i.e. non looping checks for pending IO etc.).
 
-Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics
-of a subchannel ( e.g. channel paths ).
+Store Subchannel and Modify Subchannel can be used to examine and modify
+operating characteristics of a subchannel (e.g. channel paths).
 
 Other IO related Terms:
 Sysplex: S390's Clustering Technology
-QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet,
-this architecture is also designed to be forward compatible with up & coming 64 bit machines.
+QDIO: S390's new high speed IO architecture to support devices such as gigabit
+ethernet, this architecture is also designed to be forward compatible with
+upcoming 64 bit machines.
 
 
 General Concepts 
@@ -1406,37 +1418,40 @@ sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers
 Interface (OEMI).
 
 This byte wide Parallel channel path/bus has parity & data on the "Bus" cable 
-& control lines on the "Tag" cable. These can operate in byte multiplex mode for
-sharing between several slow devices or burst mode & monopolize the channel for the
-whole burst. Up to 256 devices can be addressed  on one of these cables. These cables are
-about one inch in diameter. The maximum unextended length supported by these cables is
-125 Meters but this can be extended up to 2km with a fibre optic channel extended 
-such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however
-some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec.
+and control lines on the "Tag" cable. These can operate in byte multiplex mode
+for sharing between several slow devices or burst mode and monopolize the
+channel for the whole burst. Up to 256 devices can be addressed on one of these
+cables. These cables are about one inch in diameter. The maximum unextended
+length supported by these cables is 125 Meters but this can be extended up to
+2km with a fibre optic channel extended such as a 3044. The maximum burst speed
+supported is 4.5 megabytes per second. However, some really old processors
+support only transfer rates of 3.0, 2.0 & 1.0 MB/sec.
 One of these paths can be daisy chained to up to 8 control units.
 
 
 ESCON if fibre optic it is also called FICON 
-Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers
-for communication at a signaling rate of up to 200 megabits/sec. As 10bits are transferred
-for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once
-control info & CRC are added. ESCON only operates in burst mode.
+Was introduced by IBM in 1990. Has 2 fibre optic cables and uses either leds or
+lasers for communication at a signaling rate of up to 200 megabits/sec. As
+10bits are transferred for every 8 bits info this drops to 160 megabits/sec
+and to 18.6 Megabytes/sec once control info and CRC are added. ESCON only
+operates in burst mode.
  
-ESCONs typical max cable length is 3km for the led version & 20km for the laser version
-known as XDF ( extended distance facility ). This can be further extended by using an
-ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is
-serial it uses a packet switching architecture the standard Bus & Tag control protocol
-is however present within the packets. Up to 256 devices can be attached to each control
-unit that uses one of these interfaces.
+ESCONs typical max cable length is 3km for the led version and 20km for the
+laser version known as XDF (extended distance facility). This can be further
+extended by using an ESCON director which triples the above mentioned ranges.
+Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture,
+the standard Bus & Tag control protocol is however present within the packets.
+Up to 256 devices can be attached to each control unit that uses one of these
+interfaces.
 
 Common 390 Devices include:
 Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters,
-Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console ).
+Consoles 3270 & 3215 (a teletype emulated under linux for a line mode console).
 DASD's direct access storage devices ( otherwise known as hard disks ).
 Tape Drives.
 CTC ( Channel to Channel Adapters ),
 ESCON or Parallel Cables used as a very high speed serial link
-between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
+between 2 machines.
 
 
 Debugging IO on s/390 & z/Architecture under VM
@@ -1475,9 +1490,9 @@ or the halt subchannels
 or TR HSCH 7C08-7C09
 MSCH's ,STSCH's I think you can guess the rest
 
-Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the reader of another
-VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you
- a look at the output.
+A good trick is tracing all the IO's and CCWS and spooling them into the reader
+of another VM guest so he can ftp the logfile back to his own machine. I'll do
+a small bit of this and give you a look at the output.
 
 1) Spool stdout to VM reader
 SP PRT TO (another vm guest ) or * for the local vm guest
@@ -1593,8 +1608,8 @@ undisplay : undo's display's
 
 info breakpoints: shows all current breakpoints
 
-info stack: shows stack back trace ( if this doesn't work too well, I'll show you the
-stacktrace by hand below ).
+info stack: shows stack back trace (if this doesn't work too well, I'll show
+you the stacktrace by hand below).
 
 info locals: displays local variables.
 
@@ -1619,7 +1634,8 @@ next: like step except this will not step into subroutines
 stepi: steps a single machine code instruction.
 e.g. stepi 100
 
-nexti: steps a single machine code instruction but will not step into subroutines.
+nexti: steps a single machine code instruction but will not step into
+subroutines.
 
 finish: will run until exit of the current routine
 
@@ -1721,7 +1737,8 @@ e.g.
 outputs:
 $1 = 11 
 
-You might now be thinking that the line above didn't work, something extra had to be done.
+You might now be thinking that the line above didn't work, something extra had
+to be done.
 (gdb) call fflush(stdout)
 hello world$2 = 0
 As an aside the debugger also calls malloc & free under the hood 
@@ -1804,26 +1821,17 @@ man gdb or info gdb.
 core dumps
 ----------
 What a core dump ?,
-A core dump is a file generated by the kernel ( if allowed ) which contains the registers,
-& all active pages of the program which has crashed.
-From this file gdb will allow you to look at the registers & stack trace & memory of the
-program as if it just crashed on your system, it is usually called core & created in the
-current working directory.
-This is very useful in that a customer can mail a core dump to a technical support department
-& the technical support department can reconstruct what happened.
-Provided they have an identical copy of this program with debugging symbols compiled in &
-the source base of this build is available.
-In short it is far more useful than something like a crash log could ever hope to be.
-
-In theory all that is missing to restart a core dumped program is a kernel patch which
-will do the following.
-1) Make a new kernel task structure
-2) Reload all the dumped pages back into the kernel's memory management structures.
-3) Do the required clock fixups
-4) Get all files & network connections for the process back into an identical state ( really difficult ).
-5) A few more difficult things I haven't thought of.
-
-
+A core dump is a file generated by the kernel (if allowed) which contains the
+registers and all active pages of the program which has crashed.
+From this file gdb will allow you to look at the registers, stack trace and
+memory of the program as if it just crashed on your system. It is usually
+called core and created in the current working directory.
+This is very useful in that a customer can mail a core dump to a technical
+support department and the technical support department can reconstruct what
+happened. Provided they have an identical copy of this program with debugging
+symbols compiled in and the source base of this build is available.
+In short it is far more useful than something like a crash log could ever hope
+to be.
 
 Why have I never seen one ?.
 Probably because you haven't used the command 
@@ -1868,7 +1876,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
 #3  0x5167e6 in readline_internal_char () at readline.c:454
 #4  0x5168ee in readline_internal_charloop () at readline.c:507
 #5  0x51692c in readline_internal () at readline.c:521
-#6  0x5164fe in readline (prompt=0x7ffff810 "\177\81ÿ\81øx\177\81ÿ\81÷\81Ø\177\81ÿ\81øx\81À")
+#6  0x5164fe in readline (prompt=0x7ffff810)
     at readline.c:349
 #7  0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1,
     annotation_suffix=0x4d6b44 "prompt") at top.c:2091
@@ -1929,8 +1937,8 @@ cat /proc/sys/net/ipv4/ip_forward
 On my machine now outputs
 1
 IP forwarding is on.
-There is a lot of useful info in here best found by going in & having a look around,
-so I'll take you through some entries I consider important.
+There is a lot of useful info in here best found by going in and having a look
+around, so I'll take you through some entries I consider important.
 
 All the processes running on the machine have their own entry defined by
 /proc/<pid>
@@ -2060,7 +2068,8 @@ if the device doesn't say up
 try
 /etc/rc.d/init.d/network start 
 ( this starts the network stack & hopefully calls ifconfig tr0 up ).
-ifconfig looks at the output of /proc/net/dev & presents it in a more presentable form
+ifconfig looks at the output of /proc/net/dev and presents it in a more
+presentable form.
 Now ping the device from a machine in the same subnet.
 if the RX packets count & TX packets counts don't increment you probably
 have problems.
@@ -2086,34 +2095,6 @@ of the device.
 See the manpage chandev.8 &type cat /proc/chandev for more info.
 
 
-
-Starting points for debugging scripting languages etc.
-======================================================
-
-bash/sh
-
-bash -x <scriptname>
-e.g. bash -x /usr/bin/bashbug
-displays the following lines as it executes them.
-+ MACHINE=i586
-+ OS=linux-gnu
-+ CC=gcc
-+ CFLAGS= -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' -DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H   -I. -I. -I./lib -O2 -pipe
-+ RELEASE=2.01
-+ PATCHLEVEL=1
-+ RELSTATUS=release
-+ MACHTYPE=i586-pc-linux-gnu   
-
-perl -d <scriptname> runs the perlscript in a fully interactive debugger
-<like gdb>.
-Type 'h' in the debugger for help.
-
-for debugging java type
-jdb <filename> another fully interactive gdb style debugger.
-& type ? in the debugger for help.
-
-
-
 SysRq
 =====
 This is now supported by linux for s/390 & z/Architecture.
index b15036b1890cae7031b56c4718edbd5baddfacbb..5fa2e3035509cf533cd4d7d3ad92fbe8fe5b0897 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -726,10 +726,14 @@ KBUILD_CFLAGS     += $(call cc-option, -femit-struct-debug-baseonly) \
 endif
 
 ifdef CONFIG_FUNCTION_TRACER
+ifndef CC_FLAGS_FTRACE
+CC_FLAGS_FTRACE := -pg
+endif
+export CC_FLAGS_FTRACE
 ifdef CONFIG_HAVE_FENTRY
 CC_USING_FENTRY        := $(call cc-option, -mfentry -DCC_USING_FENTRY)
 endif
-KBUILD_CFLAGS  += -pg $(CC_USING_FENTRY)
+KBUILD_CFLAGS  += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY)
 KBUILD_AFLAGS  += $(CC_USING_FENTRY)
 ifdef CONFIG_DYNAMIC_FTRACE
        ifdef CONFIG_HAVE_C_RECORDMCOUNT
index 68b68d755fdfe46c0a9aecad0cebef4e1e079487..373cd5badf1cf8eea7ff7c65610b0a4ee2bfd5b1 100644 (file)
@@ -66,6 +66,7 @@ config S390
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select ARCH_HAS_GCOV_PROFILE_ALL
+       select ARCH_HAS_SG_CHAIN
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_INLINE_READ_LOCK
        select ARCH_INLINE_READ_LOCK_BH
@@ -116,7 +117,6 @@ config S390
        select HAVE_BPF_JIT if 64BIT && PACK_STACK
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
-       select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DYNAMIC_FTRACE if 64BIT
        select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
@@ -151,7 +151,6 @@ config S390
        select TTY
        select VIRT_CPU_ACCOUNTING
        select VIRT_TO_BUS
-       select ARCH_HAS_SG_CHAIN
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
@@ -185,6 +184,10 @@ config HAVE_MARCH_ZEC12_FEATURES
        def_bool n
        select HAVE_MARCH_Z196_FEATURES
 
+config HAVE_MARCH_Z13_FEATURES
+       def_bool n
+       select HAVE_MARCH_ZEC12_FEATURES
+
 choice
        prompt "Processor type"
        default MARCH_G5
@@ -244,6 +247,14 @@ config MARCH_ZEC12
          2827 series). The kernel will be slightly faster but will not work on
          older machines.
 
+config MARCH_Z13
+       bool "IBM z13"
+       select HAVE_MARCH_Z13_FEATURES if 64BIT
+       help
+         Select this to enable optimizations for IBM z13 (2964 series).
+         The kernel will be slightly faster but will not work on older
+         machines.
+
 endchoice
 
 config MARCH_G5_TUNE
@@ -267,6 +278,9 @@ config MARCH_Z196_TUNE
 config MARCH_ZEC12_TUNE
        def_bool TUNE_ZEC12 || MARCH_ZEC12 && TUNE_DEFAULT
 
+config MARCH_Z13_TUNE
+       def_bool TUNE_Z13 || MARCH_Z13 && TUNE_DEFAULT
+
 choice
        prompt "Tune code generation"
        default TUNE_DEFAULT
@@ -305,6 +319,9 @@ config TUNE_Z196
 config TUNE_ZEC12
        bool "IBM zBC12 and zEC12"
 
+config TUNE_Z13
+       bool "IBM z13"
+
 endchoice
 
 config 64BIT
@@ -356,14 +373,14 @@ config SMP
          Even if you don't know what to do here, say Y.
 
 config NR_CPUS
-       int "Maximum number of CPUs (2-256)"
-       range 2 256
+       int "Maximum number of CPUs (2-512)"
+       range 2 512
        depends on SMP
        default "32" if !64BIT
        default "64" if 64BIT
        help
          This allows you to specify the maximum number of CPUs which this
-         kernel will support. The maximum supported value is 256 and the
+         kernel will support. The maximum supported value is 512 and the
          minimum value which makes sense is 2.
 
          This is purely to save memory - each supported CPU adds
@@ -378,17 +395,26 @@ config HOTPLUG_CPU
          can be controlled through /sys/devices/system/cpu/cpu#.
          Say N if you want to disable CPU hotplug.
 
+config SCHED_SMT
+       def_bool n
+
 config SCHED_MC
        def_bool n
 
 config SCHED_BOOK
+       def_bool n
+
+config SCHED_TOPOLOGY
        def_bool y
-       prompt "Book scheduler support"
+       prompt "Topology scheduler support"
        depends on SMP
+       select SCHED_SMT
        select SCHED_MC
+       select SCHED_BOOK
        help
-         Book scheduler support improves the CPU scheduler's decision making
-         when dealing with machines that have several books.
+         Topology scheduler support improves the CPU scheduler's decision
+         making when dealing with machines that have multi-threading,
+         multiple cores or multiple books.
 
 source kernel/Kconfig.preempt
 
index 878e67973151b54c93c5eb078d53a4beef330f10..acb6859c6a95f4ea9e787f39e8131c093d8700f9 100644 (file)
@@ -42,6 +42,7 @@ mflags-$(CONFIG_MARCH_Z9_109) := -march=z9-109
 mflags-$(CONFIG_MARCH_Z10)    := -march=z10
 mflags-$(CONFIG_MARCH_Z196)   := -march=z196
 mflags-$(CONFIG_MARCH_ZEC12)  := -march=zEC12
+mflags-$(CONFIG_MARCH_Z13)   := -march=z13
 
 aflags-y += $(mflags-y)
 cflags-y += $(mflags-y)
@@ -53,6 +54,7 @@ cflags-$(CONFIG_MARCH_Z9_109_TUNE)    += -mtune=z9-109
 cflags-$(CONFIG_MARCH_Z10_TUNE)                += -mtune=z10
 cflags-$(CONFIG_MARCH_Z196_TUNE)       += -mtune=z196
 cflags-$(CONFIG_MARCH_ZEC12_TUNE)      += -mtune=zEC12
+cflags-$(CONFIG_MARCH_Z13_TUNE)        += -mtune=z13
 
 #KBUILD_IMAGE is necessary for make rpm
 KBUILD_IMAGE   :=arch/s390/boot/image
@@ -85,6 +87,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 endif
 
+ifdef CONFIG_FUNCTION_TRACER
+# make use of hotpatch feature if the compiler supports it
+cc_hotpatch    := -mhotpatch=0,3
+ifeq ($(call cc-option-yn,$(cc_hotpatch)),y)
+CC_FLAGS_FTRACE := $(cc_hotpatch)
+KBUILD_AFLAGS  += -DCC_USING_HOTPATCH
+KBUILD_CFLAGS  += -DCC_USING_HOTPATCH
+endif
+endif
+
 KBUILD_CFLAGS  += -mbackchain -msoft-float $(cflags-y)
 KBUILD_CFLAGS  += -pipe -fno-strength-reduce -Wno-sign-compare
 KBUILD_AFLAGS  += $(aflags-y)
index 57cbaff1f39778b98b1de870e34f99cc14043687..42506b371b74144886e42a9ec21d43edcf680566 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
+#include <asm/sclp.h>
 #include <asm/ipl.h>
 #include "sizes.h"
 
@@ -63,8 +64,6 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_unxz.c"
 #endif
 
-extern _sclp_print_early(const char *);
-
 static int puts(const char *s)
 {
        _sclp_print_early(s);
index 9432d0f202ef20a6bd5ee8300d8f1ac654029c60..64707750c78071e1d0168de0f26e357d368d9507 100644 (file)
@@ -555,7 +555,6 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_SLUB_DEBUG_ON=y
 CONFIG_SLUB_STATS=y
-CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_RB=y
@@ -563,6 +562,7 @@ CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 CONFIG_DEBUG_PER_CPU_MAPS=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_DETECT_HUNG_TASK=y
+CONFIG_PANIC_ON_OOPS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
index 219dca6ea92684485e56d68c4b6d04719217a4f2..5c3097272cd8c8eec82d252a9210dcf15cf3c36a 100644 (file)
@@ -540,6 +540,7 @@ CONFIG_UNUSED_SYMBOLS=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
+CONFIG_PANIC_ON_OOPS=y
 CONFIG_TIMER_STATS=y
 CONFIG_RCU_TORTURE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
index 822c2f2e0c25d4adac076344e9ceafc971196082..bda70f1ffd2c59346839d3b293c07eac0f021853 100644 (file)
@@ -537,6 +537,7 @@ CONFIG_FRAME_WARN=1024
 CONFIG_UNUSED_SYMBOLS=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_ON_OOPS=y
 CONFIG_TIMER_STATS=y
 CONFIG_RCU_TORTURE_TEST=m
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
index 9d63051ebec42556cc545835cdb5cb6fe4d94f7a..1b0184a0f7f213d4557337a18cc5b39adfdd494c 100644 (file)
@@ -71,6 +71,7 @@ CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_ON_OOPS=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
 # CONFIG_FTRACE is not set
index 1f272b24fc0bf9393d44939ea2b225a84e36ea2a..5566ce80abdbf7c97bec630d480b583b324bf82d 100644 (file)
@@ -134,7 +134,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-       const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
        if (unlikely(need_fallback(sctx->key_len))) {
                crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
@@ -159,7 +159,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-       const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
        if (unlikely(need_fallback(sctx->key_len))) {
                crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
index 785c5f24d6f9e5c7b99d71a11b7eee9dc6e670e2..83ef702d2403686bb00c24251bdf1806fd0ad057 100644 (file)
@@ -14,7 +14,6 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
 CONFIG_MEMCG=y
 CONFIG_MEMCG_SWAP=y
 CONFIG_CGROUP_SCHED=y
@@ -22,12 +21,8 @@ CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_CGROUP=y
 CONFIG_NAMESPACES=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
-CONFIG_RD_XZ=y
-CONFIG_RD_LZO=y
-CONFIG_RD_LZ4=y
 CONFIG_EXPERT=y
+CONFIG_BPF_SYSCALL=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
index 06f8d95a16cdc9767d4538ea1798c32bfac73187..2ee25ba252d68ab98efdcd7a525ae0b29778950d 100644 (file)
@@ -5,3 +5,4 @@
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 
 s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
+s390_hypfs-objs += hypfs_diag0c.o
index b34b5ab90a313b77bd0561503d882af311a50c7d..eecde500ed49e2726cc2ed8d0b20e37459075217 100644 (file)
@@ -37,6 +37,10 @@ extern int hypfs_vm_init(void);
 extern void hypfs_vm_exit(void);
 extern int hypfs_vm_create_files(struct dentry *root);
 
+/* VM diagnose 0c */
+int hypfs_diag0c_init(void);
+void hypfs_diag0c_exit(void);
+
 /* Set Partition-Resource Parameter */
 int hypfs_sprp_init(void);
 void hypfs_sprp_exit(void);
@@ -49,7 +53,6 @@ struct hypfs_dbfs_data {
        void                    *buf_free_ptr;
        size_t                  size;
        struct hypfs_dbfs_file  *dbfs_file;
-       struct kref             kref;
 };
 
 struct hypfs_dbfs_file {
@@ -61,8 +64,6 @@ struct hypfs_dbfs_file {
                                           unsigned long);
 
        /* Private data for hypfs_dbfs.c */
-       struct hypfs_dbfs_data  *data;
-       struct delayed_work     data_free_work;
        struct mutex            lock;
        struct dentry           *dentry;
 };
index 47fe1055c714a34c1348b3a734705a408aff081b..752f6df3e6974a823e9bcbdb044d3e5381d9bb4e 100644 (file)
@@ -17,33 +17,16 @@ static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
        data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return NULL;
-       kref_init(&data->kref);
        data->dbfs_file = f;
        return data;
 }
 
-static void hypfs_dbfs_data_free(struct kref *kref)
+static void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data)
 {
-       struct hypfs_dbfs_data *data;
-
-       data = container_of(kref, struct hypfs_dbfs_data, kref);
        data->dbfs_file->data_free(data->buf_free_ptr);
        kfree(data);
 }
 
-static void data_free_delayed(struct work_struct *work)
-{
-       struct hypfs_dbfs_data *data;
-       struct hypfs_dbfs_file *df;
-
-       df = container_of(work, struct hypfs_dbfs_file, data_free_work.work);
-       mutex_lock(&df->lock);
-       data = df->data;
-       df->data = NULL;
-       mutex_unlock(&df->lock);
-       kref_put(&data->kref, hypfs_dbfs_data_free);
-}
-
 static ssize_t dbfs_read(struct file *file, char __user *buf,
                         size_t size, loff_t *ppos)
 {
@@ -56,28 +39,21 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,
 
        df = file_inode(file)->i_private;
        mutex_lock(&df->lock);
-       if (!df->data) {
-               data = hypfs_dbfs_data_alloc(df);
-               if (!data) {
-                       mutex_unlock(&df->lock);
-                       return -ENOMEM;
-               }
-               rc = df->data_create(&data->buf, &data->buf_free_ptr,
-                                    &data->size);
-               if (rc) {
-                       mutex_unlock(&df->lock);
-                       kfree(data);
-                       return rc;
-               }
-               df->data = data;
-               schedule_delayed_work(&df->data_free_work, HZ);
+       data = hypfs_dbfs_data_alloc(df);
+       if (!data) {
+               mutex_unlock(&df->lock);
+               return -ENOMEM;
+       }
+       rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size);
+       if (rc) {
+               mutex_unlock(&df->lock);
+               kfree(data);
+               return rc;
        }
-       data = df->data;
-       kref_get(&data->kref);
        mutex_unlock(&df->lock);
 
        rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
-       kref_put(&data->kref, hypfs_dbfs_data_free);
+       hypfs_dbfs_data_free(data);
        return rc;
 }
 
@@ -108,7 +84,6 @@ int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
        if (IS_ERR(df->dentry))
                return PTR_ERR(df->dentry);
        mutex_init(&df->lock);
-       INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed);
        return 0;
 }
 
diff --git a/arch/s390/hypfs/hypfs_diag0c.c b/arch/s390/hypfs/hypfs_diag0c.c
new file mode 100644 (file)
index 0000000..d4c0d37
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Hypervisor filesystem for Linux on s390
+ *
+ * Diag 0C implementation
+ *
+ * Copyright IBM Corp. 2014
+ */
+
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <asm/hypfs.h>
+#include "hypfs.h"
+
+#define DBFS_D0C_HDR_VERSION 0
+
+/*
+ * Execute diagnose 0c in 31 bit mode
+ */
+static void diag0c(struct hypfs_diag0c_entry *entry)
+{
+       asm volatile (
+#ifdef CONFIG_64BIT
+               "       sam31\n"
+               "       diag    %0,%0,0x0c\n"
+               "       sam64\n"
+#else
+               "       diag %0,%0,0x0c\n"
+#endif
+               : /* no output register */
+               : "a" (entry)
+               : "memory");
+}
+
+/*
+ * Get hypfs_diag0c_entry from CPU vector and store diag0c data
+ */
+static void diag0c_fn(void *data)
+{
+       diag0c(((void **) data)[smp_processor_id()]);
+}
+
+/*
+ * Allocate buffer and store diag 0c data
+ */
+static void *diag0c_store(unsigned int *count)
+{
+       struct hypfs_diag0c_data *diag0c_data;
+       unsigned int cpu_count, cpu, i;
+       void **cpu_vec;
+
+       get_online_cpus();
+       cpu_count = num_online_cpus();
+       cpu_vec = kmalloc(sizeof(*cpu_vec) * num_possible_cpus(), GFP_KERNEL);
+       if (!cpu_vec)
+               goto fail_put_online_cpus;
+       /* Note: Diag 0c needs 8 byte alignment and real storage */
+       diag0c_data = kzalloc(sizeof(struct hypfs_diag0c_hdr) +
+                             cpu_count * sizeof(struct hypfs_diag0c_entry),
+                             GFP_KERNEL | GFP_DMA);
+       if (!diag0c_data)
+               goto fail_kfree_cpu_vec;
+       i = 0;
+       /* Fill CPU vector for each online CPU */
+       for_each_online_cpu(cpu) {
+               diag0c_data->entry[i].cpu = cpu;
+               cpu_vec[cpu] = &diag0c_data->entry[i++];
+       }
+       /* Collect data all CPUs */
+       on_each_cpu(diag0c_fn, cpu_vec, 1);
+       *count = cpu_count;
+       kfree(cpu_vec);
+       put_online_cpus();
+       return diag0c_data;
+
+fail_kfree_cpu_vec:
+       kfree(cpu_vec);
+fail_put_online_cpus:
+       put_online_cpus();
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * Hypfs DBFS callback: Free diag 0c data
+ */
+static void dbfs_diag0c_free(const void *data)
+{
+       kfree(data);
+}
+
+/*
+ * Hypfs DBFS callback: Create diag 0c data
+ */
+static int dbfs_diag0c_create(void **data, void **data_free_ptr, size_t *size)
+{
+       struct hypfs_diag0c_data *diag0c_data;
+       unsigned int count;
+
+       diag0c_data = diag0c_store(&count);
+       if (IS_ERR(diag0c_data))
+               return PTR_ERR(diag0c_data);
+       memset(&diag0c_data->hdr, 0, sizeof(diag0c_data->hdr));
+       get_tod_clock_ext(diag0c_data->hdr.tod_ext);
+       diag0c_data->hdr.len = count * sizeof(struct hypfs_diag0c_entry);
+       diag0c_data->hdr.version = DBFS_D0C_HDR_VERSION;
+       diag0c_data->hdr.count = count;
+       *data = diag0c_data;
+       *data_free_ptr = diag0c_data;
+       *size = diag0c_data->hdr.len + sizeof(struct hypfs_diag0c_hdr);
+       return 0;
+}
+
+/*
+ * Hypfs DBFS file structure
+ */
+static struct hypfs_dbfs_file dbfs_file_0c = {
+       .name           = "diag_0c",
+       .data_create    = dbfs_diag0c_create,
+       .data_free      = dbfs_diag0c_free,
+};
+
+/*
+ * Initialize diag 0c interface for z/VM
+ */
+int __init hypfs_diag0c_init(void)
+{
+       if (!MACHINE_IS_VM)
+               return 0;
+       return hypfs_dbfs_create_file(&dbfs_file_0c);
+}
+
+/*
+ * Shutdown diag 0c interface for z/VM
+ */
+void hypfs_diag0c_exit(void)
+{
+       if (!MACHINE_IS_VM)
+               return;
+       hypfs_dbfs_remove_file(&dbfs_file_0c);
+}
index c952b981e4f28885223c7f77b51ada2299f03c6a..4c8008dd938e8d0eb5c4fdc18b35b2cfc90f6807 100644 (file)
@@ -482,10 +482,14 @@ static int __init hypfs_init(void)
                rc = -ENODATA;
                goto fail_hypfs_vm_exit;
        }
+       if (hypfs_diag0c_init()) {
+               rc = -ENODATA;
+               goto fail_hypfs_sprp_exit;
+       }
        s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
        if (!s390_kobj) {
                rc = -ENOMEM;
-               goto fail_hypfs_sprp_exit;
+               goto fail_hypfs_diag0c_exit;
        }
        rc = register_filesystem(&hypfs_type);
        if (rc)
@@ -494,6 +498,8 @@ static int __init hypfs_init(void)
 
 fail_filesystem:
        kobject_put(s390_kobj);
+fail_hypfs_diag0c_exit:
+       hypfs_diag0c_exit();
 fail_hypfs_sprp_exit:
        hypfs_sprp_exit();
 fail_hypfs_vm_exit:
@@ -510,6 +516,7 @@ static void __exit hypfs_exit(void)
 {
        unregister_filesystem(&hypfs_type);
        kobject_put(s390_kobj);
+       hypfs_diag0c_exit();
        hypfs_sprp_exit();
        hypfs_vm_exit();
        hypfs_diag_exit();
index cb700d54bd832a91256803b35bbff06adc3a95d3..5243a8679a1dcb7cc69037714fabba64c652dcf1 100644 (file)
@@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val)
        return cc;
 }
 
+/* Store CPU counter multiple for the MT utilization counter set */
+static inline int stcctm5(u64 num, u64 *val)
+{
+       typedef struct { u64 _[num]; } addrtype;
+       int cc;
+
+       asm volatile (
+               "       .insn   rsy,0xeb0000000017,%2,5,%1\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
+               : "=d" (cc), "=Q" (*(addrtype *) val)  : "d" (num) : "cc");
+       return cc;
+}
+
 /* Query sampling information */
 static inline int qsi(struct hws_qsi_info_block *info)
 {
index f6e43d39e3d82e7c86e771078b752a88f998c481..c9df40b5c0ac1915eac7d6a794b25f7f9d6173b5 100644 (file)
@@ -163,8 +163,8 @@ extern unsigned int vdso_enabled;
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-extern unsigned long randomize_et_dyn(unsigned long base);
-#define ELF_ET_DYN_BASE                (randomize_et_dyn(STACK_TOP / 3 * 2))
+extern unsigned long randomize_et_dyn(void);
+#define ELF_ET_DYN_BASE                randomize_et_dyn()
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports. */
@@ -209,7 +209,9 @@ do {                                                                \
 } while (0)
 #endif /* CONFIG_COMPAT */
 
-#define STACK_RND_MASK 0x7ffUL
+extern unsigned long mmap_rnd_mask;
+
+#define STACK_RND_MASK (mmap_rnd_mask)
 
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
index abb618f1ead25fcad51b90bc1cffd61ef8dde67b..836c56290499b84c0dad7785e9aa5979d68ed0bf 100644 (file)
@@ -3,8 +3,12 @@
 
 #define ARCH_SUPPORTS_FTRACE_OPS 1
 
+#ifdef CC_USING_HOTPATCH
+#define MCOUNT_INSN_SIZE       6
+#else
 #define MCOUNT_INSN_SIZE       24
 #define MCOUNT_RETURN_FIXUP    18
+#endif
 
 #ifndef __ASSEMBLY__
 
@@ -37,17 +41,28 @@ struct ftrace_insn {
 static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
        /* jg .+24 */
        insn->opc = 0xc0f4;
        insn->disp = MCOUNT_INSN_SIZE / 2;
 #endif
+#endif
 }
 
 static inline int is_ftrace_nop(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       if (insn->disp == 0)
+               return 1;
+#else
        if (insn->disp == MCOUNT_INSN_SIZE / 2)
                return 1;
+#endif
 #endif
        return 0;
 }
index 346b1c85ffb40d890078550dc72c2dedcb275a2e..58642fd29c878c8d1fb5d384ecf58427b553552e 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 
 #define JUMP_LABEL_NOP_SIZE 6
+#define JUMP_LABEL_NOP_OFFSET 2
 
 #ifdef CONFIG_64BIT
 #define ASM_PTR ".quad"
 #define ASM_ALIGN ".balign 4"
 #endif
 
+/*
+ * We use a brcl 0,2 instruction for jump labels at compile time so it
+ * can be easily distinguished from a hotpatch generated instruction.
+ */
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm_volatile_goto("0:   brcl 0,0\n"
+       asm_volatile_goto("0:   brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
                ".pushsection __jump_table, \"aw\"\n"
                ASM_ALIGN "\n"
                ASM_PTR " 0b, %l[label], %0\n"
index ffb1d8ce97aeac9e1f98d5a1d9bf1549c7d2418b..0441ec24ae87cddb7f8bad10b5c68273ba4e6f42 100644 (file)
@@ -1758,6 +1758,10 @@ extern int s390_enable_sie(void);
 extern int s390_enable_skey(void);
 extern void s390_reset_cmma(struct mm_struct *mm);
 
+/* s390 has a private copy of get unmapped area to deal with cache synonyms */
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+
 /*
  * No page table caches to initialise
  */
index bed05ea7ec27eb236cc65b2007379fa6f61fb865..e7cbbdcdee1337cf8cefa5fbe74dab2e174eadf2 100644 (file)
@@ -215,10 +215,7 @@ static inline unsigned short stap(void)
 /*
  * Give up the time slice of the virtual PU.
  */
-static inline void cpu_relax(void)
-{
-       barrier();
-}
+void cpu_relax(void);
 
 #define cpu_relax_lowlatency()  barrier()
 
index 804578587a7a87e6e0b9eb56a1aee121bf9d2fdf..72786067b300528632dfb2a6f30917fddc48a2e1 100644 (file)
@@ -15,5 +15,6 @@ struct reset_call {
 
 extern void register_reset_call(struct reset_call *reset);
 extern void unregister_reset_call(struct reset_call *reset);
-extern void s390_reset_system(void (*func)(void *), void *data);
+extern void s390_reset_system(void (*fn_pre)(void),
+                             void (*fn_post)(void *), void *data);
 #endif /* _ASM_S390_RESET_H */
index 1aba89b53cb9e1e8614524c8786a7dced2960278..edb453cfc2c635b36dcae386cdac5b317e02ddaa 100644 (file)
@@ -27,7 +27,7 @@ struct sclp_ipl_info {
 };
 
 struct sclp_cpu_entry {
-       u8 address;
+       u8 core_id;
        u8 reserved0[2];
        u8 : 3;
        u8 siif : 1;
@@ -51,6 +51,9 @@ int sclp_cpu_deconfigure(u8 cpu);
 unsigned long long sclp_get_rnmax(void);
 unsigned long long sclp_get_rzm(void);
 unsigned int sclp_get_max_cpu(void);
+unsigned int sclp_get_mtid(u8 cpu_type);
+unsigned int sclp_get_mtid_max(void);
+unsigned int sclp_get_mtid_prev(void);
 int sclp_sdias_blk_count(void);
 int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
 int sclp_chp_configure(struct chp_id chpid);
@@ -68,4 +71,6 @@ void sclp_early_detect(void);
 int sclp_has_siif(void);
 unsigned int sclp_get_ibc(void);
 
+long _sclp_print_early(const char *);
+
 #endif /* _ASM_S390_SCLP_H */
index 7736fdd725953c862f3df931723ed355d8b23f8b..b8d1e54b473308738167c1246b72734c5e0d71cc 100644 (file)
@@ -57,6 +57,7 @@ extern void detect_memory_memblock(void);
 #define MACHINE_FLAG_TE                (1UL << 15)
 #define MACHINE_FLAG_TLB_LC    (1UL << 17)
 #define MACHINE_FLAG_VX                (1UL << 18)
+#define MACHINE_FLAG_CAD       (1UL << 19)
 
 #define MACHINE_IS_VM          (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM         (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -80,6 +81,7 @@ extern void detect_memory_memblock(void);
 #define MACHINE_HAS_TE         (0)
 #define MACHINE_HAS_TLB_LC     (0)
 #define MACHINE_HAS_VX         (0)
+#define MACHINE_HAS_CAD                (0)
 #else /* CONFIG_64BIT */
 #define MACHINE_HAS_IEEE       (1)
 #define MACHINE_HAS_CSP                (1)
@@ -93,6 +95,7 @@ extern void detect_memory_memblock(void);
 #define MACHINE_HAS_TE         (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
 #define MACHINE_HAS_TLB_LC     (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
 #define MACHINE_HAS_VX         (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
+#define MACHINE_HAS_CAD                (S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
 #endif /* CONFIG_64BIT */
 
 /*
index fad4ae23ece05a6e7d922d75033c4fb347c6357d..ec60cf7fa0a247ec7f13d70480c3312386823096 100644 (file)
@@ -16,6 +16,7 @@
 #define SIGP_SET_ARCHITECTURE       18
 #define SIGP_COND_EMERGENCY_SIGNAL   19
 #define SIGP_SENSE_RUNNING          21
+#define SIGP_SET_MULTI_THREADING     22
 #define SIGP_STORE_ADDITIONAL_STATUS 23
 
 /* SIGP condition codes */
index 762d4f88af5ae3453402e99fd216bd612e2d4377..b3bd0282dd9870c93f1ddd66472afc4170b356a1 100644 (file)
@@ -16,6 +16,8 @@
 #define raw_smp_processor_id() (S390_lowcore.cpu_nr)
 
 extern struct mutex smp_cpu_state_mutex;
+extern unsigned int smp_cpu_mt_shift;
+extern unsigned int smp_cpu_mtid;
 
 extern int __cpu_up(unsigned int cpu, struct task_struct *tidle);
 
@@ -35,6 +37,8 @@ extern void smp_fill_possible_mask(void);
 
 #else /* CONFIG_SMP */
 
+#define smp_cpu_mtid   0
+
 static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
 {
        func(data);
index f92428e459f8b8cc7352321332ca52431f55f51f..73f12d21af4dc4f5ce3856e95761b8521b5a2e5b 100644 (file)
@@ -90,7 +90,11 @@ struct sysinfo_2_2_2 {
        unsigned short cpus_reserved;
        char name[8];
        unsigned int caf;
-       char reserved_2[16];
+       char reserved_2[8];
+       unsigned char mt_installed;
+       unsigned char mt_general;
+       unsigned char mt_psmtid;
+       char reserved_3[5];
        unsigned short cpus_dedicated;
        unsigned short cpus_shared;
 };
@@ -120,26 +124,28 @@ struct sysinfo_3_2_2 {
 
 extern int topology_max_mnest;
 
-#define TOPOLOGY_CPU_BITS      64
+#define TOPOLOGY_CORE_BITS     64
 #define TOPOLOGY_NR_MAG                6
 
-struct topology_cpu {
-       unsigned char reserved0[4];
+struct topology_core {
+       unsigned char nl;
+       unsigned char reserved0[3];
        unsigned char :6;
        unsigned char pp:2;
        unsigned char reserved1;
        unsigned short origin;
-       unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
+       unsigned long mask[TOPOLOGY_CORE_BITS / BITS_PER_LONG];
 };
 
 struct topology_container {
-       unsigned char reserved[7];
+       unsigned char nl;
+       unsigned char reserved[6];
        unsigned char id;
 };
 
 union topology_entry {
        unsigned char nl;
-       struct topology_cpu cpu;
+       struct topology_core cpu;
        struct topology_container container;
 };
 
index 56af53093d24d3660ed1267e229eccb6925b56ef..c4fbb9527c5ca2b553ca98c3f7887ea236fdff1c 100644 (file)
@@ -9,9 +9,11 @@ struct cpu;
 #ifdef CONFIG_SCHED_BOOK
 
 struct cpu_topology_s390 {
+       unsigned short thread_id;
        unsigned short core_id;
        unsigned short socket_id;
        unsigned short book_id;
+       cpumask_t thread_mask;
        cpumask_t core_mask;
        cpumask_t book_mask;
 };
@@ -19,6 +21,8 @@ struct cpu_topology_s390 {
 extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
 
 #define topology_physical_package_id(cpu)      (cpu_topology[cpu].socket_id)
+#define topology_thread_id(cpu)                        (cpu_topology[cpu].thread_id)
+#define topology_thread_cpumask(cpu)           (&cpu_topology[cpu].thread_mask)
 #define topology_core_id(cpu)                  (cpu_topology[cpu].core_id)
 #define topology_core_cpumask(cpu)             (&cpu_topology[cpu].core_mask)
 #define topology_book_id(cpu)                  (cpu_topology[cpu].book_id)
index 37998b449531eda3d0a1b415428e7db3d81ab1ba..b3fe12d8dd87f7e642cfd7a3a4836f583996bed7 100644 (file)
@@ -1,16 +1,19 @@
 /*
- * IOCTL interface for hypfs
+ * Structures for hypfs interface
  *
  * Copyright IBM Corp. 2013
  *
  * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
-#ifndef _ASM_HYPFS_CTL_H
-#define _ASM_HYPFS_CTL_H
+#ifndef _ASM_HYPFS_H
+#define _ASM_HYPFS_H
 
 #include <linux/types.h>
 
+/*
+ * IOCTL for binary interface /sys/kernel/debug/diag_304
+ */
 struct hypfs_diag304 {
        __u32   args[2];
        __u64   data;
@@ -22,4 +25,30 @@ struct hypfs_diag304 {
 #define HYPFS_DIAG304 \
        _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304)
 
+/*
+ * Structures for binary interface /sys/kernel/debug/diag_0c
+ */
+struct hypfs_diag0c_hdr {
+       __u64   len;            /* Length of diag0c buffer without header */
+       __u16   version;        /* Version of header */
+       char    reserved1[6];   /* Reserved */
+       char    tod_ext[16];    /* TOD clock for diag0c */
+       __u64   count;          /* Number of entries (CPUs) in diag0c array */
+       char    reserved2[24];  /* Reserved */
+};
+
+struct hypfs_diag0c_entry {
+       char    date[8];        /* MM/DD/YY in EBCDIC */
+       char    time[8];        /* HH:MM:SS in EBCDIC */
+       __u64   virtcpu;        /* Virtual time consumed by the virt CPU (us) */
+       __u64   totalproc;      /* Total of virtual and simulation time (us) */
+       __u32   cpu;            /* Linux logical CPU number */
+       __u32   reserved;       /* Align to 8 byte */
+};
+
+struct hypfs_diag0c_data {
+       struct hypfs_diag0c_hdr         hdr;            /* 64 byte header */
+       struct hypfs_diag0c_entry       entry[];        /* diag0c entry array */
+};
+
 #endif
index 204c43a4c245dd1835915adbbae39da494c2d947..31fab2676fe9216ab5e7338283b2c7004924e919 100644 (file)
@@ -4,8 +4,8 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 # Don't trace early setup code and tracing code
-CFLAGS_REMOVE_early.o = -pg
-CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
 endif
 
 #
index 797a823a22755d9b76f8c12717e043226c7395bd..f74a53d339b0b79b361304cffa9dacf8aaac2106 100644 (file)
@@ -97,7 +97,8 @@ ENTRY(diag308_reset)
        lg      %r4,0(%r4)              # Save PSW
        sturg   %r4,%r3                 # Use sturg, because of large pages
        lghi    %r1,1
-       diag    %r1,%r1,0x308
+       lghi    %r0,0
+       diag    %r0,%r1,0x308
 .Lrestart_part2:
        lhi     %r0,0                   # Load r0 with zero
        lhi     %r1,2                   # Use mode 2 = ESAME (dump)
index c0b03c28d15717448f4f713c083bbd891861f42b..632fa06ea162c567923044ddf4e3ced0339d24bd 100644 (file)
@@ -5,37 +5,11 @@
  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
-#include <linux/notifier.h>
 #include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/cacheinfo.h>
 #include <asm/facility.h>
 
-struct cache {
-       unsigned long size;
-       unsigned int line_size;
-       unsigned int associativity;
-       unsigned int nr_sets;
-       unsigned int level   : 3;
-       unsigned int type    : 2;
-       unsigned int private : 1;
-       struct list_head list;
-};
-
-struct cache_dir {
-       struct kobject *kobj;
-       struct cache_index_dir *index;
-};
-
-struct cache_index_dir {
-       struct kobject kobj;
-       int cpu;
-       struct cache *cache;
-       struct cache_index_dir *next;
-};
-
 enum {
        CACHE_SCOPE_NOTEXISTS,
        CACHE_SCOPE_PRIVATE,
@@ -44,10 +18,10 @@ enum {
 };
 
 enum {
-       CACHE_TYPE_SEPARATE,
-       CACHE_TYPE_DATA,
-       CACHE_TYPE_INSTRUCTION,
-       CACHE_TYPE_UNIFIED,
+       CTYPE_SEPARATE,
+       CTYPE_DATA,
+       CTYPE_INSTRUCTION,
+       CTYPE_UNIFIED,
 };
 
 enum {
@@ -70,37 +44,60 @@ struct cache_info {
 };
 
 #define CACHE_MAX_LEVEL 8
-
 union cache_topology {
        struct cache_info ci[CACHE_MAX_LEVEL];
        unsigned long long raw;
 };
 
 static const char * const cache_type_string[] = {
-       "Data",
+       "",
        "Instruction",
+       "Data",
+       "",
        "Unified",
 };
 
-static struct cache_dir *cache_dir_cpu[NR_CPUS];
-static LIST_HEAD(cache_list);
+static const enum cache_type cache_type_map[] = {
+       [CTYPE_SEPARATE] = CACHE_TYPE_SEPARATE,
+       [CTYPE_DATA] = CACHE_TYPE_DATA,
+       [CTYPE_INSTRUCTION] = CACHE_TYPE_INST,
+       [CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
+};
 
 void show_cacheinfo(struct seq_file *m)
 {
-       struct cache *cache;
-       int index = 0;
+       struct cpu_cacheinfo *this_cpu_ci;
+       struct cacheinfo *cache;
+       int idx;
 
-       list_for_each_entry(cache, &cache_list, list) {
-               seq_printf(m, "cache%-11d: ", index);
+       get_online_cpus();
+       this_cpu_ci = get_cpu_cacheinfo(cpumask_any(cpu_online_mask));
+       for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
+               cache = this_cpu_ci->info_list + idx;
+               seq_printf(m, "cache%-11d: ", idx);
                seq_printf(m, "level=%d ", cache->level);
                seq_printf(m, "type=%s ", cache_type_string[cache->type]);
-               seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared");
-               seq_printf(m, "size=%luK ", cache->size >> 10);
-               seq_printf(m, "line_size=%u ", cache->line_size);
-               seq_printf(m, "associativity=%d", cache->associativity);
+               seq_printf(m, "scope=%s ",
+                          cache->disable_sysfs ? "Shared" : "Private");
+               seq_printf(m, "size=%dK ", cache->size >> 10);
+               seq_printf(m, "line_size=%u ", cache->coherency_line_size);
+               seq_printf(m, "associativity=%d", cache->ways_of_associativity);
                seq_puts(m, "\n");
-               index++;
        }
+       put_online_cpus();
+}
+
+static inline enum cache_type get_cache_type(struct cache_info *ci, int level)
+{
+       if (level >= CACHE_MAX_LEVEL)
+               return CACHE_TYPE_NOCACHE;
+
+       ci += level;
+
+       if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE)
+               return CACHE_TYPE_NOCACHE;
+
+       return cache_type_map[ci->type];
 }
 
 static inline unsigned long ecag(int ai, int li, int ti)
@@ -113,277 +110,79 @@ static inline unsigned long ecag(int ai, int li, int ti)
        return val;
 }
 
-static int __init cache_add(int level, int private, int type)
+static void ci_leaf_init(struct cacheinfo *this_leaf, int private,
+                        enum cache_type type, unsigned int level)
 {
-       struct cache *cache;
-       int ti;
+       int ti, num_sets;
+       int cpu = smp_processor_id();
 
-       cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-       if (!cache)
-               return -ENOMEM;
-       if (type == CACHE_TYPE_INSTRUCTION)
+       if (type == CACHE_TYPE_INST)
                ti = CACHE_TI_INSTRUCTION;
        else
                ti = CACHE_TI_UNIFIED;
-       cache->size = ecag(EXTRACT_SIZE, level, ti);
-       cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
-       cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
-       cache->nr_sets = cache->size / cache->associativity;
-       cache->nr_sets /= cache->line_size;
-       cache->private = private;
-       cache->level = level + 1;
-       cache->type = type - 1;
-       list_add_tail(&cache->list, &cache_list);
-       return 0;
-}
-
-static void __init cache_build_info(void)
-{
-       struct cache *cache, *next;
-       union cache_topology ct;
-       int level, private, rc;
-
-       ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
-       for (level = 0; level < CACHE_MAX_LEVEL; level++) {
-               switch (ct.ci[level].scope) {
-               case CACHE_SCOPE_SHARED:
-                       private = 0;
-                       break;
-               case CACHE_SCOPE_PRIVATE:
-                       private = 1;
-                       break;
-               default:
-                       return;
-               }
-               if (ct.ci[level].type == CACHE_TYPE_SEPARATE) {
-                       rc  = cache_add(level, private, CACHE_TYPE_DATA);
-                       rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION);
-               } else {
-                       rc = cache_add(level, private, ct.ci[level].type);
-               }
-               if (rc)
-                       goto error;
-       }
-       return;
-error:
-       list_for_each_entry_safe(cache, next, &cache_list, list) {
-               list_del(&cache->list);
-               kfree(cache);
-       }
-}
-
-static struct cache_dir *cache_create_cache_dir(int cpu)
-{
-       struct cache_dir *cache_dir;
-       struct kobject *kobj = NULL;
-       struct device *dev;
-
-       dev = get_cpu_device(cpu);
-       if (!dev)
-               goto out;
-       kobj = kobject_create_and_add("cache", &dev->kobj);
-       if (!kobj)
-               goto out;
-       cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL);
-       if (!cache_dir)
-               goto out;
-       cache_dir->kobj = kobj;
-       cache_dir_cpu[cpu] = cache_dir;
-       return cache_dir;
-out:
-       kobject_put(kobj);
-       return NULL;
-}
-
-static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj)
-{
-       return container_of(kobj, struct cache_index_dir, kobj);
-}
-
-static void cache_index_release(struct kobject *kobj)
-{
-       struct cache_index_dir *index;
-
-       index = kobj_to_cache_index_dir(kobj);
-       kfree(index);
-}
-
-static ssize_t cache_index_show(struct kobject *kobj,
-                               struct attribute *attr, char *buf)
-{
-       struct kobj_attribute *kobj_attr;
-
-       kobj_attr = container_of(attr, struct kobj_attribute, attr);
-       return kobj_attr->show(kobj, kobj_attr, buf);
-}
-
-#define DEFINE_CACHE_ATTR(_name, _format, _value)                      \
-static ssize_t cache_##_name##_show(struct kobject *kobj,              \
-                                   struct kobj_attribute *attr,        \
-                                   char *buf)                          \
-{                                                                      \
-       struct cache_index_dir *index;                                  \
-                                                                       \
-       index = kobj_to_cache_index_dir(kobj);                          \
-       return sprintf(buf, _format, _value);                           \
-}                                                                      \
-static struct kobj_attribute cache_##_name##_attr =                    \
-       __ATTR(_name, 0444, cache_##_name##_show, NULL);
 
-DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10);
-DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size);
-DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets);
-DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity);
-DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]);
-DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level);
+       this_leaf->level = level + 1;
+       this_leaf->type = type;
+       this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
+       this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY,
+                                               level, ti);
+       this_leaf->size = ecag(EXTRACT_SIZE, level, ti);
 
-static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf)
-{
-       struct cache_index_dir *index;
-       int len;
-
-       index = kobj_to_cache_index_dir(kobj);
-       len = type ?
-               cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) :
-               cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu));
-       len += sprintf(&buf[len], "\n");
-       return len;
-}
-
-static ssize_t shared_cpu_map_show(struct kobject *kobj,
-                                  struct kobj_attribute *attr, char *buf)
-{
-       return shared_cpu_map_func(kobj, 0, buf);
+       num_sets = this_leaf->size / this_leaf->coherency_line_size;
+       num_sets /= this_leaf->ways_of_associativity;
+       this_leaf->number_of_sets = num_sets;
+       cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
+       if (!private)
+               this_leaf->disable_sysfs = true;
 }
-static struct kobj_attribute cache_shared_cpu_map_attr =
-       __ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL);
 
-static ssize_t shared_cpu_list_show(struct kobject *kobj,
-                                   struct kobj_attribute *attr, char *buf)
+int init_cache_level(unsigned int cpu)
 {
-       return shared_cpu_map_func(kobj, 1, buf);
-}
-static struct kobj_attribute cache_shared_cpu_list_attr =
-       __ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL);
-
-static struct attribute *cache_index_default_attrs[] = {
-       &cache_type_attr.attr,
-       &cache_size_attr.attr,
-       &cache_number_of_sets_attr.attr,
-       &cache_ways_of_associativity_attr.attr,
-       &cache_level_attr.attr,
-       &cache_coherency_line_size_attr.attr,
-       &cache_shared_cpu_map_attr.attr,
-       &cache_shared_cpu_list_attr.attr,
-       NULL,
-};
-
-static const struct sysfs_ops cache_index_ops = {
-       .show = cache_index_show,
-};
-
-static struct kobj_type cache_index_type = {
-       .sysfs_ops = &cache_index_ops,
-       .release = cache_index_release,
-       .default_attrs = cache_index_default_attrs,
-};
-
-static int cache_create_index_dir(struct cache_dir *cache_dir,
-                                 struct cache *cache, int index, int cpu)
-{
-       struct cache_index_dir *index_dir;
-       int rc;
-
-       index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL);
-       if (!index_dir)
-               return -ENOMEM;
-       index_dir->cache = cache;
-       index_dir->cpu = cpu;
-       rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type,
-                                 cache_dir->kobj, "index%d", index);
-       if (rc)
-               goto out;
-       index_dir->next = cache_dir->index;
-       cache_dir->index = index_dir;
-       return 0;
-out:
-       kfree(index_dir);
-       return rc;
-}
+       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+       unsigned int level = 0, leaves = 0;
+       union cache_topology ct;
+       enum cache_type ctype;
 
-static int cache_add_cpu(int cpu)
-{
-       struct cache_dir *cache_dir;
-       struct cache *cache;
-       int rc, index = 0;
+       if (!this_cpu_ci)
+               return -EINVAL;
 
-       if (list_empty(&cache_list))
-               return 0;
-       cache_dir = cache_create_cache_dir(cpu);
-       if (!cache_dir)
-               return -ENOMEM;
-       list_for_each_entry(cache, &cache_list, list) {
-               if (!cache->private)
+       ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
+       do {
+               ctype = get_cache_type(&ct.ci[0], level);
+               if (ctype == CACHE_TYPE_NOCACHE)
                        break;
-               rc = cache_create_index_dir(cache_dir, cache, index, cpu);
-               if (rc)
-                       return rc;
-               index++;
-       }
-       return 0;
-}
+               /* Separate instruction and data caches */
+               leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
+       } while (++level < CACHE_MAX_LEVEL);
 
-static void cache_remove_cpu(int cpu)
-{
-       struct cache_index_dir *index, *next;
-       struct cache_dir *cache_dir;
+       this_cpu_ci->num_levels = level;
+       this_cpu_ci->num_leaves = leaves;
 
-       cache_dir = cache_dir_cpu[cpu];
-       if (!cache_dir)
-               return;
-       index = cache_dir->index;
-       while (index) {
-               next = index->next;
-               kobject_put(&index->kobj);
-               index = next;
-       }
-       kobject_put(cache_dir->kobj);
-       kfree(cache_dir);
-       cache_dir_cpu[cpu] = NULL;
+       return 0;
 }
 
-static int cache_hotplug(struct notifier_block *nfb, unsigned long action,
-                        void *hcpu)
+int populate_cache_leaves(unsigned int cpu)
 {
-       int cpu = (long)hcpu;
-       int rc = 0;
+       unsigned int level, idx, pvt;
+       union cache_topology ct;
+       enum cache_type ctype;
+       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+       struct cacheinfo *this_leaf = this_cpu_ci->info_list;
 
-       switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_ONLINE:
-               rc = cache_add_cpu(cpu);
-               if (rc)
-                       cache_remove_cpu(cpu);
-               break;
-       case CPU_DEAD:
-               cache_remove_cpu(cpu);
-               break;
+       ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
+       for (idx = 0, level = 0; level < this_cpu_ci->num_levels &&
+            idx < this_cpu_ci->num_leaves; idx++, level++) {
+               if (!this_leaf)
+                       return -EINVAL;
+
+               pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0;
+               ctype = get_cache_type(&ct.ci[0], level);
+               if (ctype == CACHE_TYPE_SEPARATE) {
+                       ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level);
+                       ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level);
+               } else {
+                       ci_leaf_init(this_leaf++, pvt, ctype, level);
+               }
        }
-       return rc ? NOTIFY_BAD : NOTIFY_OK;
-}
-
-static int __init cache_init(void)
-{
-       int cpu;
-
-       if (!test_facility(34))
-               return 0;
-       cache_build_info();
-
-       cpu_notifier_register_begin();
-       for_each_online_cpu(cpu)
-               cache_add_cpu(cpu);
-       __hotcpu_notifier(cache_hotplug, 0);
-       cpu_notifier_register_done();
        return 0;
 }
-device_initcall(cache_init);
index f3762937dd82ee8afcc2c0fddae6397e2be863fa..533430307da8f55cafb70b69441691fdf2be6702 100644 (file)
@@ -137,7 +137,7 @@ enum {
        INSTR_RSI_RRP,
        INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
        INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
-       INSTR_RSY_RDRM,
+       INSTR_RSY_RDRM, INSTR_RSY_RMRD,
        INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
        INSTR_RS_RURD,
        INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
@@ -226,7 +226,6 @@ static const struct s390_operand operands[] =
        [U16_32] = { 16, 32, 0 },
        [J16_16] = { 16, 16, OPERAND_PCREL },
        [J16_32] = { 16, 32, OPERAND_PCREL },
-       [I16_32] = { 16, 32, OPERAND_SIGNED },
        [I24_24] = { 24, 24, OPERAND_SIGNED },
        [J32_16] = { 32, 16, OPERAND_PCREL },
        [I32_16] = { 32, 16, OPERAND_SIGNED },
@@ -308,6 +307,7 @@ static const unsigned char formats[][7] = {
        [INSTR_RSY_AARD]  = { 0xff, A_8,A_12,D20_20,B_16,0,0 },
        [INSTR_RSY_CCRD]  = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
        [INSTR_RSY_RDRM]  = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
+       [INSTR_RSY_RMRD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
        [INSTR_RSY_RRRD]  = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
        [INSTR_RSY_RURD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
        [INSTR_RS_AARD]   = { 0xff, A_8,A_12,D_20,B_16,0,0 },
@@ -451,7 +451,8 @@ enum {
        LONG_INSN_VERLLV,
        LONG_INSN_VESRAV,
        LONG_INSN_VESRLV,
-       LONG_INSN_VSBCBI
+       LONG_INSN_VSBCBI,
+       LONG_INSN_STCCTM
 };
 
 static char *long_insn_name[] = {
@@ -531,6 +532,7 @@ static char *long_insn_name[] = {
        [LONG_INSN_VESRAV] = "vesrav",
        [LONG_INSN_VESRLV] = "vesrlv",
        [LONG_INSN_VSBCBI] = "vsbcbi",
+       [LONG_INSN_STCCTM] = "stcctm",
 };
 
 static struct s390_insn opcode[] = {
@@ -1656,6 +1658,7 @@ static struct s390_insn opcode_eb[] = {
        { "lric", 0x60, INSTR_RSY_RDRM },
        { "stric", 0x61, INSTR_RSY_RDRM },
        { "mric", 0x62, INSTR_RSY_RDRM },
+       { { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD },
 #endif
        { "rll", 0x1d, INSTR_RSY_RRRD },
        { "mvclu", 0x8e, INSTR_RSY_RRRD },
index 302ac1f7f8e7693db6d547f544acfd84d1d4d357..70a3294509018e33c49d6b0a383c841d79d2f3af 100644 (file)
@@ -393,9 +393,27 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
        if (test_facility(129))
                S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
+       if (test_facility(128))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_CAD;
 #endif
 }
 
+static int __init nocad_setup(char *str)
+{
+       S390_lowcore.machine_flags &= ~MACHINE_FLAG_CAD;
+       return 0;
+}
+early_param("nocad", nocad_setup);
+
+static int __init cad_init(void)
+{
+       if (MACHINE_HAS_CAD)
+               /* Enable problem state CAD. */
+               __ctl_set_bit(2, 3);
+       return 0;
+}
+early_initcall(cad_init);
+
 static __init void rescue_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
index 8e61393c827577d4e2d8fef7067ebb053435b49e..834df047d35f67e1367710ab3a0b27b29ef2ea1b 100644 (file)
@@ -71,9 +71,11 @@ struct s390_mmap_arg_struct;
 struct fadvise64_64_args;
 struct old_sigaction;
 
+long sys_rt_sigreturn(void);
+long sys_sigreturn(void);
+
 long sys_s390_personality(unsigned int personality);
 long sys_s390_runtime_instr(int command, int signum);
-
 long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
 long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
 #endif /* _ENTRY_H */
index b86bb8823f15192030f227d2c9cc189d66804d50..82c19899574f83070158c09c5eed5b438bc092c1 100644 (file)
  *     lg      %r14,8(%r15)            # offset 18
  * The jg instruction branches to offset 24 to skip as many instructions
  * as possible.
+ * In case we use gcc's hotpatch feature the original and also the disabled
+ * function prologue contains only a single six byte instruction and looks
+ * like this:
+ * >   brcl    0,0                     # offset 0
+ * To enable ftrace the code gets patched like above and afterwards looks
+ * like this:
+ * >   brasl   %r0,ftrace_caller       # offset 0
  */
 
 unsigned long ftrace_plt;
@@ -59,62 +66,71 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
                    unsigned long addr)
 {
-       struct ftrace_insn insn;
-       unsigned short op;
-       void *from, *to;
-       size_t size;
-
-       ftrace_generate_nop_insn(&insn);
-       size = sizeof(insn);
-       from = &insn;
-       to = (void *) rec->ip;
-       if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
+       struct ftrace_insn orig, new, old;
+
+       if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       /*
-        * If we find a breakpoint instruction, a kprobe has been placed
-        * at the beginning of the function. We write the constant
-        * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original
-        * instruction so that the kprobes handler can execute a nop, if it
-        * reaches this breakpoint.
-        */
-       if (op == BREAKPOINT_INSTRUCTION) {
-               size -= 2;
-               from += 2;
-               to += 2;
-               insn.disp = KPROBE_ON_FTRACE_NOP;
+       if (addr == MCOUNT_ADDR) {
+               /* Initial code replacement */
+#ifdef CC_USING_HOTPATCH
+               /* We expect to see brcl 0,0 */
+               ftrace_generate_nop_insn(&orig);
+#else
+               /* We expect to see stg r14,8(r15) */
+               orig.opc = 0xe3e0;
+               orig.disp = 0xf0080024;
+#endif
+               ftrace_generate_nop_insn(&new);
+       } else if (old.opc == BREAKPOINT_INSTRUCTION) {
+               /*
+                * If we find a breakpoint instruction, a kprobe has been
+                * placed at the beginning of the function. We write the
+                * constant KPROBE_ON_FTRACE_NOP into the remaining four
+                * bytes of the original instruction so that the kprobes
+                * handler can execute a nop, if it reaches this breakpoint.
+                */
+               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
+               orig.disp = KPROBE_ON_FTRACE_CALL;
+               new.disp = KPROBE_ON_FTRACE_NOP;
+       } else {
+               /* Replace ftrace call with a nop. */
+               ftrace_generate_call_insn(&orig, rec->ip);
+               ftrace_generate_nop_insn(&new);
        }
-       if (probe_kernel_write(to, from, size))
+       /* Verify that the to be replaced code matches what we expect. */
+       if (memcmp(&orig, &old, sizeof(old)))
+               return -EINVAL;
+       if (probe_kernel_write((void *) rec->ip, &new, sizeof(new)))
                return -EPERM;
        return 0;
 }
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
-       struct ftrace_insn insn;
-       unsigned short op;
-       void *from, *to;
-       size_t size;
-
-       ftrace_generate_call_insn(&insn, rec->ip);
-       size = sizeof(insn);
-       from = &insn;
-       to = (void *) rec->ip;
-       if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
+       struct ftrace_insn orig, new, old;
+
+       if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
-       /*
-        * If we find a breakpoint instruction, a kprobe has been placed
-        * at the beginning of the function. We write the constant
-        * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original
-        * instruction so that the kprobes handler can execute a brasl if it
-        * reaches this breakpoint.
-        */
-       if (op == BREAKPOINT_INSTRUCTION) {
-               size -= 2;
-               from += 2;
-               to += 2;
-               insn.disp = KPROBE_ON_FTRACE_CALL;
+       if (old.opc == BREAKPOINT_INSTRUCTION) {
+               /*
+                * If we find a breakpoint instruction, a kprobe has been
+                * placed at the beginning of the function. We write the
+                * constant KPROBE_ON_FTRACE_CALL into the remaining four
+                * bytes of the original instruction so that the kprobes
+                * handler can execute a brasl if it reaches this breakpoint.
+                */
+               new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
+               orig.disp = KPROBE_ON_FTRACE_NOP;
+               new.disp = KPROBE_ON_FTRACE_CALL;
+       } else {
+               /* Replace nop with an ftrace call. */
+               ftrace_generate_nop_insn(&orig);
+               ftrace_generate_call_insn(&new, rec->ip);
        }
-       if (probe_kernel_write(to, from, size))
+       /* Verify that the to be replaced code matches what we expect. */
+       if (memcmp(&orig, &old, sizeof(old)))
+               return -EINVAL;
+       if (probe_kernel_write((void *) rec->ip, &new, sizeof(new)))
                return -EPERM;
        return 0;
 }
index d62eee11f0b54240339d898fbf95d4299c011545..132f4c9ade603002138b3075a8a7c16576b17fa2 100644 (file)
@@ -436,7 +436,9 @@ ENTRY(startup_kdump)
 # followed by the facility words.
 
 #if defined(CONFIG_64BIT)
-#if defined(CONFIG_MARCH_ZEC12)
+#if defined(CONFIG_MARCH_Z13)
+       .long 3, 0xc100eff2, 0xf46ce800, 0x00400000
+#elif defined(CONFIG_MARCH_ZEC12)
        .long 3, 0xc100eff2, 0xf46ce800, 0x00400000
 #elif defined(CONFIG_MARCH_Z196)
        .long 2, 0xc100eff2, 0xf46c0000
index 39badb9ca0b30c6b7b32ce720165e85c3c33319a..5c8651f3650937c06c8cfcd0f306104b89435b59 100644 (file)
@@ -2074,7 +2074,8 @@ static void do_reset_calls(void)
 
 u32 dump_prefix_page;
 
-void s390_reset_system(void (*func)(void *), void *data)
+void s390_reset_system(void (*fn_pre)(void),
+                      void (*fn_post)(void *), void *data)
 {
        struct _lowcore *lc;
 
@@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data)
        /* Store status at absolute zero */
        store_status();
 
+       /* Call function before reset */
+       if (fn_pre)
+               fn_pre();
        do_reset_calls();
-       if (func)
-               func(data);
+       /* Call function after reset */
+       if (fn_post)
+               fn_post(data);
 }
index b987ab2c1541afb1866e11949c156e6b62c9b67c..cb2d51e779dfafe0bf02077bdd68918dde731511 100644 (file)
@@ -22,31 +22,66 @@ struct insn_args {
        enum jump_label_type type;
 };
 
+static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
+{
+       /* brcl 0,0 */
+       insn->opcode = 0xc004;
+       insn->offset = 0;
+}
+
+static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
+{
+       /* brcl 15,offset */
+       insn->opcode = 0xc0f4;
+       insn->offset = (entry->target - entry->code) >> 1;
+}
+
+static void jump_label_bug(struct jump_entry *entry, struct insn *insn)
+{
+       unsigned char *ipc = (unsigned char *)entry->code;
+       unsigned char *ipe = (unsigned char *)insn;
+
+       pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
+       pr_emerg("Found:    %02x %02x %02x %02x %02x %02x\n",
+                ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
+       pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
+                ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
+       panic("Corrupted kernel text");
+}
+
+static struct insn orignop = {
+       .opcode = 0xc004,
+       .offset = JUMP_LABEL_NOP_OFFSET >> 1,
+};
+
 static void __jump_label_transform(struct jump_entry *entry,
-                                  enum jump_label_type type)
+                                  enum jump_label_type type,
+                                  int init)
 {
-       struct insn insn;
-       int rc;
+       struct insn old, new;
 
        if (type == JUMP_LABEL_ENABLE) {
-               /* brcl 15,offset */
-               insn.opcode = 0xc0f4;
-               insn.offset = (entry->target - entry->code) >> 1;
+               jump_label_make_nop(entry, &old);
+               jump_label_make_branch(entry, &new);
        } else {
-               /* brcl 0,0 */
-               insn.opcode = 0xc004;
-               insn.offset = 0;
+               jump_label_make_branch(entry, &old);
+               jump_label_make_nop(entry, &new);
        }
-
-       rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE);
-       WARN_ON_ONCE(rc < 0);
+       if (init) {
+               if (memcmp((void *)entry->code, &orignop, sizeof(orignop)))
+                       jump_label_bug(entry, &old);
+       } else {
+               if (memcmp((void *)entry->code, &old, sizeof(old)))
+                       jump_label_bug(entry, &old);
+       }
+       probe_kernel_write((void *)entry->code, &new, sizeof(new));
 }
 
 static int __sm_arch_jump_label_transform(void *data)
 {
        struct insn_args *args = data;
 
-       __jump_label_transform(args->entry, args->type);
+       __jump_label_transform(args->entry, args->type, 0);
        return 0;
 }
 
@@ -64,7 +99,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
 void arch_jump_label_transform_static(struct jump_entry *entry,
                                      enum jump_label_type type)
 {
-       __jump_label_transform(entry, type);
+       __jump_label_transform(entry, type, 1);
 }
 
 #endif
index 1e4c710dfb9233dafa10a07fcb769b6028758a66..f516edc1fbe31a952839102db45ed9a1b71bdab7 100644 (file)
@@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p)
                /*
                 * If kprobes patches the instruction that is morphed by
                 * ftrace make sure that kprobes always sees the branch
-                * "jg .+24" that skips the mcount block
+                * "jg .+24" that skips the mcount block or the "brcl 0,0"
+                * in case of hotpatch.
                 */
                ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
                p->ainsn.is_ftrace_insn = 1;
index 4685337fa7c6bf9464630f5ec648ca65e53cea0c..fb0901ec4306b833920b4f1b9386afc64c5573d0 100644 (file)
@@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void)
        return 0;
 }
 arch_initcall(machine_kdump_pm_init);
-#endif
 
 /*
  * Start kdump: We expect here that a store status has been done on our CPU
  */
 static void __do_machine_kdump(void *image)
 {
-#ifdef CONFIG_CRASH_DUMP
        int (*start_kdump)(int) = (void *)((struct kimage *) image)->start;
 
-       setup_regs();
        __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
        start_kdump(1);
-#endif
 }
+#endif
 
 /*
  * Check if kdump checksums are valid: We call purgatory with parameter "0"
@@ -249,18 +246,18 @@ static void __do_machine_kexec(void *data)
  */
 static void __machine_kexec(void *data)
 {
-       struct kimage *image = data;
-
        __arch_local_irq_stosm(0x04); /* enable DAT */
        pfault_fini();
        tracing_off();
        debug_locks_off();
-       if (image->type == KEXEC_TYPE_CRASH) {
+#ifdef CONFIG_CRASH_DUMP
+       if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) {
+
                lgr_info_log();
-               s390_reset_system(__do_machine_kdump, data);
-       } else {
-               s390_reset_system(__do_machine_kexec, data);
-       }
+               s390_reset_system(setup_regs, __do_machine_kdump, data);
+       } else
+#endif
+               s390_reset_system(NULL, __do_machine_kexec, data);
        disabled_wait((unsigned long) __builtin_return_address(0));
 }
 
index b6dfc5bfcb892227407302def2c35963f450cae0..e499370fbccb328561e6ef5ab0bfe35afb4a0b51 100644 (file)
@@ -27,7 +27,9 @@ ENTRY(ftrace_caller)
        .globl  ftrace_regs_caller
        .set    ftrace_regs_caller,ftrace_caller
        lgr     %r1,%r15
+#ifndef CC_USING_HOTPATCH
        aghi    %r0,MCOUNT_RETURN_FIXUP
+#endif
        aghi    %r15,-STACK_FRAME_SIZE
        stg     %r1,__SF_BACKCHAIN(%r15)
        stg     %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
index aa7a83948c7b13fda4712ec1081808f849ef2b23..13fc0978ca7e77cca706e442fe474e5d97d54a4b 100644 (file)
@@ -79,6 +79,14 @@ void release_thread(struct task_struct *dead_task)
 {
 }
 
+#ifdef CONFIG_64BIT
+void arch_release_task_struct(struct task_struct *tsk)
+{
+       if (tsk->thread.vxrs)
+               kfree(tsk->thread.vxrs);
+}
+#endif
+
 int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
                unsigned long arg, struct task_struct *p)
 {
@@ -243,13 +251,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
        ret = PAGE_ALIGN(mm->brk + brk_rnd());
        return (ret > mm->brk) ? ret : mm->brk;
 }
-
-unsigned long randomize_et_dyn(unsigned long base)
-{
-       unsigned long ret;
-
-       if (!(current->flags & PF_RANDOMIZE))
-               return base;
-       ret = PAGE_ALIGN(base + brk_rnd());
-       return (ret > base) ? ret : base;
-}
index dbdd33ee010204f0e03c9c1fd48ad30acad59b4c..26108232fcaaf049f4e4caa3938e537af5066ac6 100644 (file)
@@ -8,16 +8,24 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp.h>
 #include <linux/seq_file.h>
 #include <linux/delay.h>
 #include <linux/cpu.h>
 #include <asm/elf.h>
 #include <asm/lowcore.h>
 #include <asm/param.h>
+#include <asm/smp.h>
 
 static DEFINE_PER_CPU(struct cpuid, cpu_id);
 
+void cpu_relax(void)
+{
+       if (!smp_cpu_mtid && MACHINE_HAS_DIAG44)
+               asm volatile("diag 0,0,0x44");
+       barrier();
+}
+EXPORT_SYMBOL(cpu_relax);
+
 /*
  * cpu_init - initializes state that is per-CPU.
  */
index a41f2c99dcc85dbac9a2193960a6de63ce769120..7e77e03378f38f2e770e369982c92a1382e461b1 100644 (file)
@@ -294,7 +294,8 @@ ENTRY(_sclp_print_early)
 #ifdef CONFIG_64BIT
        tm      LC_AR_MODE_ID,1
        jno     .Lesa3
-       lmh     %r6,%r15,96(%r15)               # store upper register halves
+       lgfr    %r2,%r2                         # sign extend return value
+       lmh     %r6,%r15,96(%r15)               # restore upper register halves
        ahi     %r15,80
 .Lesa3:
 #endif
index 4e532c67832fddc904aa050f66370cec25c97a26..bfac77ada4f28137b5545d9268d37346eb3af0ff 100644 (file)
@@ -810,6 +810,9 @@ static void __init setup_hwcaps(void)
        case 0x2828:
                strcpy(elf_platform, "zEC12");
                break;
+       case 0x2964:
+               strcpy(elf_platform, "z13");
+               break;
        }
 }
 
index 0b499f5cbe19c18d43c9360297407e86ed6a1212..a668993ff577f95d40aff6f474e082374967a79b 100644 (file)
@@ -71,9 +71,30 @@ struct pcpu {
 };
 
 static u8 boot_cpu_type;
-static u16 boot_cpu_address;
 static struct pcpu pcpu_devices[NR_CPUS];
 
+unsigned int smp_cpu_mt_shift;
+EXPORT_SYMBOL(smp_cpu_mt_shift);
+
+unsigned int smp_cpu_mtid;
+EXPORT_SYMBOL(smp_cpu_mtid);
+
+static unsigned int smp_max_threads __initdata = -1U;
+
+static int __init early_nosmt(char *s)
+{
+       smp_max_threads = 1;
+       return 0;
+}
+early_param("nosmt", early_nosmt);
+
+static int __init early_smt(char *s)
+{
+       get_option(&s, &smp_max_threads);
+       return 0;
+}
+early_param("smt", early_smt);
+
 /*
  * The smp_cpu_state_mutex must be held when changing the state or polarization
  * member of a pcpu data structure within the pcpu_devices arreay.
@@ -132,7 +153,7 @@ static inline int pcpu_running(struct pcpu *pcpu)
 /*
  * Find struct pcpu by cpu address.
  */
-static struct pcpu *pcpu_find_address(const struct cpumask *mask, int address)
+static struct pcpu *pcpu_find_address(const struct cpumask *mask, u16 address)
 {
        int cpu;
 
@@ -298,6 +319,32 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
        for (;;) ;
 }
 
+/*
+ * Enable additional logical cpus for multi-threading.
+ */
+static int pcpu_set_smt(unsigned int mtid)
+{
+       register unsigned long reg1 asm ("1") = (unsigned long) mtid;
+       int cc;
+
+       if (smp_cpu_mtid == mtid)
+               return 0;
+       asm volatile(
+               "       sigp    %1,0,%2 # sigp set multi-threading\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
+               : "=d" (cc) : "d" (reg1), "K" (SIGP_SET_MULTI_THREADING)
+               : "cc");
+       if (cc == 0) {
+               smp_cpu_mtid = mtid;
+               smp_cpu_mt_shift = 0;
+               while (smp_cpu_mtid >= (1U << smp_cpu_mt_shift))
+                       smp_cpu_mt_shift++;
+               pcpu_devices[0].address = stap();
+       }
+       return cc;
+}
+
 /*
  * Call function on an online CPU.
  */
@@ -512,22 +559,17 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
 
 #ifdef CONFIG_CRASH_DUMP
 
-static void __init smp_get_save_area(int cpu, u16 address)
+static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu)
 {
        void *lc = pcpu_devices[0].lowcore;
        struct save_area_ext *sa_ext;
        unsigned long vx_sa;
 
-       if (is_kdump_kernel())
-               return;
-       if (!OLDMEM_BASE && (address == boot_cpu_address ||
-                            ipl_info.type != IPL_TYPE_FCP_DUMP))
-               return;
        sa_ext = dump_save_area_create(cpu);
        if (!sa_ext)
                panic("could not allocate memory for save area\n");
-       if (address == boot_cpu_address) {
-               /* Copy the registers of the boot cpu. */
+       if (is_boot_cpu) {
+               /* Copy the registers of the boot CPU. */
                copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
                                 SAVE_AREA_BASE - PAGE_SIZE, 0);
                if (MACHINE_HAS_VX)
@@ -548,6 +590,64 @@ static void __init smp_get_save_area(int cpu, u16 address)
        free_page(vx_sa);
 }
 
+/*
+ * Collect CPU state of the previous, crashed system.
+ * There are four cases:
+ * 1) standard zfcp dump
+ *    condition: OLDMEM_BASE == NULL && ipl_info.type == IPL_TYPE_FCP_DUMP
+ *    The state for all CPUs except the boot CPU needs to be collected
+ *    with sigp stop-and-store-status. The boot CPU state is located in
+ *    the absolute lowcore of the memory stored in the HSA. The zcore code
+ *    will allocate the save area and copy the boot CPU state from the HSA.
+ * 2) stand-alone kdump for SCSI (zfcp dump with swapped memory)
+ *    condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP
+ *    The state for all CPUs except the boot CPU needs to be collected
+ *    with sigp stop-and-store-status. The firmware or the boot-loader
+ *    stored the registers of the boot CPU in the absolute lowcore in the
+ *    memory of the old system.
+ * 3) kdump and the old kernel did not store the CPU state,
+ *    or stand-alone kdump for DASD
+ *    condition: OLDMEM_BASE != NULL && !is_kdump_kernel()
+ *    The state for all CPUs except the boot CPU needs to be collected
+ *    with sigp stop-and-store-status. The kexec code or the boot-loader
+ *    stored the registers of the boot CPU in the memory of the old system.
+ * 4) kdump and the old kernel stored the CPU state
+ *    condition: OLDMEM_BASE != NULL && is_kdump_kernel()
+ *    The state of all CPUs is stored in ELF sections in the memory of the
+ *    old system. The ELF sections are picked up by the crash_dump code
+ *    via elfcorehdr_addr.
+ */
+static void __init smp_store_cpu_states(struct sclp_cpu_info *info)
+{
+       unsigned int cpu, address, i, j;
+       int is_boot_cpu;
+
+       if (is_kdump_kernel())
+               /* Previous system stored the CPU states. Nothing to do. */
+               return;
+       if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP))
+               /* No previous system present, normal boot. */
+               return;
+       /* Set multi-threading state to the previous system. */
+       pcpu_set_smt(sclp_get_mtid_prev());
+       /* Collect CPU states. */
+       cpu = 0;
+       for (i = 0; i < info->configured; i++) {
+               /* Skip CPUs with different CPU type. */
+               if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
+                       continue;
+               for (j = 0; j <= smp_cpu_mtid; j++, cpu++) {
+                       address = (info->cpu[i].core_id << smp_cpu_mt_shift) + j;
+                       is_boot_cpu = (address == pcpu_devices[0].address);
+                       if (is_boot_cpu && !OLDMEM_BASE)
+                               /* Skip boot CPU for standard zfcp dump. */
+                               continue;
+                       /* Get state for this CPu. */
+                       __smp_store_cpu_state(cpu, address, is_boot_cpu);
+               }
+       }
+}
+
 int smp_store_status(int cpu)
 {
        unsigned long vx_sa;
@@ -565,10 +665,6 @@ int smp_store_status(int cpu)
        return 0;
 }
 
-#else /* CONFIG_CRASH_DUMP */
-
-static inline void smp_get_save_area(int cpu, u16 address) { }
-
 #endif /* CONFIG_CRASH_DUMP */
 
 void smp_cpu_set_polarization(int cpu, int val)
@@ -590,11 +686,13 @@ static struct sclp_cpu_info *smp_get_cpu_info(void)
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
                use_sigp_detection = 1;
-               for (address = 0; address <= MAX_CPU_ADDRESS; address++) {
+               for (address = 0; address <= MAX_CPU_ADDRESS;
+                    address += (1U << smp_cpu_mt_shift)) {
                        if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
                            SIGP_CC_NOT_OPERATIONAL)
                                continue;
-                       info->cpu[info->configured].address = address;
+                       info->cpu[info->configured].core_id =
+                               address >> smp_cpu_mt_shift;
                        info->configured++;
                }
                info->combined = info->configured;
@@ -608,7 +706,8 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)
 {
        struct pcpu *pcpu;
        cpumask_t avail;
-       int cpu, nr, i;
+       int cpu, nr, i, j;
+       u16 address;
 
        nr = 0;
        cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
@@ -616,51 +715,76 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)
        for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
                if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
                        continue;
-               if (pcpu_find_address(cpu_present_mask, info->cpu[i].address))
-                       continue;
-               pcpu = pcpu_devices + cpu;
-               pcpu->address = info->cpu[i].address;
-               pcpu->state = (i >= info->configured) ?
-                       CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
-               smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
-               set_cpu_present(cpu, true);
-               if (sysfs_add && smp_add_present_cpu(cpu) != 0)
-                       set_cpu_present(cpu, false);
-               else
-                       nr++;
-               cpu = cpumask_next(cpu, &avail);
+               address = info->cpu[i].core_id << smp_cpu_mt_shift;
+               for (j = 0; j <= smp_cpu_mtid; j++) {
+                       if (pcpu_find_address(cpu_present_mask, address + j))
+                               continue;
+                       pcpu = pcpu_devices + cpu;
+                       pcpu->address = address + j;
+                       pcpu->state =
+                               (cpu >= info->configured*(smp_cpu_mtid + 1)) ?
+                               CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
+                       smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+                       set_cpu_present(cpu, true);
+                       if (sysfs_add && smp_add_present_cpu(cpu) != 0)
+                               set_cpu_present(cpu, false);
+                       else
+                               nr++;
+                       cpu = cpumask_next(cpu, &avail);
+                       if (cpu >= nr_cpu_ids)
+                               break;
+               }
        }
        return nr;
 }
 
 static void __init smp_detect_cpus(void)
 {
-       unsigned int cpu, c_cpus, s_cpus;
+       unsigned int cpu, mtid, c_cpus, s_cpus;
        struct sclp_cpu_info *info;
+       u16 address;
 
+       /* Get CPU information */
        info = smp_get_cpu_info();
        if (!info)
                panic("smp_detect_cpus failed to allocate memory\n");
+
+       /* Find boot CPU type */
        if (info->has_cpu_type) {
-               for (cpu = 0; cpu < info->combined; cpu++) {
-                       if (info->cpu[cpu].address != boot_cpu_address)
-                               continue;
-                       /* The boot cpu dictates the cpu type. */
-                       boot_cpu_type = info->cpu[cpu].type;
-                       break;
-               }
+               address = stap();
+               for (cpu = 0; cpu < info->combined; cpu++)
+                       if (info->cpu[cpu].core_id == address) {
+                               /* The boot cpu dictates the cpu type. */
+                               boot_cpu_type = info->cpu[cpu].type;
+                               break;
+                       }
+               if (cpu >= info->combined)
+                       panic("Could not find boot CPU type");
        }
+
+#ifdef CONFIG_CRASH_DUMP
+       /* Collect CPU state of previous system */
+       smp_store_cpu_states(info);
+#endif
+
+       /* Set multi-threading state for the current system */
+       mtid = sclp_get_mtid(boot_cpu_type);
+       mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1;
+       pcpu_set_smt(mtid);
+
+       /* Print number of CPUs */
        c_cpus = s_cpus = 0;
        for (cpu = 0; cpu < info->combined; cpu++) {
                if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type)
                        continue;
-               if (cpu < info->configured) {
-                       smp_get_save_area(c_cpus, info->cpu[cpu].address);
-                       c_cpus++;
-               } else
-                       s_cpus++;
+               if (cpu < info->configured)
+                       c_cpus += smp_cpu_mtid + 1;
+               else
+                       s_cpus += smp_cpu_mtid + 1;
        }
        pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
+
+       /* Add CPUs present at boot */
        get_online_cpus();
        __smp_rescan_cpus(info, 0);
        put_online_cpus();
@@ -696,12 +820,23 @@ static void smp_start_secondary(void *cpuvoid)
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
        struct pcpu *pcpu;
-       int rc;
+       int base, i, rc;
 
        pcpu = pcpu_devices + cpu;
        if (pcpu->state != CPU_STATE_CONFIGURED)
                return -EIO;
-       if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
+       base = cpu - (cpu % (smp_cpu_mtid + 1));
+       for (i = 0; i <= smp_cpu_mtid; i++) {
+               if (base + i < nr_cpu_ids)
+                       if (cpu_online(base + i))
+                               break;
+       }
+       /*
+        * If this is the first CPU of the core to get online
+        * do an initial CPU reset.
+        */
+       if (i > smp_cpu_mtid &&
+           pcpu_sigp_retry(pcpu_devices + base, SIGP_INITIAL_CPU_RESET, 0) !=
            SIGP_CC_ORDER_CODE_ACCEPTED)
                return -EIO;
 
@@ -774,7 +909,8 @@ void __init smp_fill_possible_mask(void)
 {
        unsigned int possible, sclp, cpu;
 
-       sclp = sclp_get_max_cpu() ?: nr_cpu_ids;
+       sclp = min(smp_max_threads, sclp_get_mtid_max() + 1);
+       sclp = sclp_get_max_cpu()*sclp ?: nr_cpu_ids;
        possible = setup_possible_cpus ?: nr_cpu_ids;
        possible = min(possible, sclp);
        for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
@@ -796,9 +932,8 @@ void __init smp_prepare_boot_cpu(void)
 {
        struct pcpu *pcpu = pcpu_devices;
 
-       boot_cpu_address = stap();
        pcpu->state = CPU_STATE_CONFIGURED;
-       pcpu->address = boot_cpu_address;
+       pcpu->address = stap();
        pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
        pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
                + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
@@ -848,7 +983,7 @@ static ssize_t cpu_configure_store(struct device *dev,
                                   const char *buf, size_t count)
 {
        struct pcpu *pcpu;
-       int cpu, val, rc;
+       int cpu, val, rc, i;
        char delim;
 
        if (sscanf(buf, "%d %c", &val, &delim) != 1)
@@ -860,29 +995,43 @@ static ssize_t cpu_configure_store(struct device *dev,
        rc = -EBUSY;
        /* disallow configuration changes of online cpus and cpu 0 */
        cpu = dev->id;
-       if (cpu_online(cpu) || cpu == 0)
+       cpu -= cpu % (smp_cpu_mtid + 1);
+       if (cpu == 0)
                goto out;
+       for (i = 0; i <= smp_cpu_mtid; i++)
+               if (cpu_online(cpu + i))
+                       goto out;
        pcpu = pcpu_devices + cpu;
        rc = 0;
        switch (val) {
        case 0:
                if (pcpu->state != CPU_STATE_CONFIGURED)
                        break;
-               rc = sclp_cpu_deconfigure(pcpu->address);
+               rc = sclp_cpu_deconfigure(pcpu->address >> smp_cpu_mt_shift);
                if (rc)
                        break;
-               pcpu->state = CPU_STATE_STANDBY;
-               smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+               for (i = 0; i <= smp_cpu_mtid; i++) {
+                       if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i))
+                               continue;
+                       pcpu[i].state = CPU_STATE_STANDBY;
+                       smp_cpu_set_polarization(cpu + i,
+                                                POLARIZATION_UNKNOWN);
+               }
                topology_expect_change();
                break;
        case 1:
                if (pcpu->state != CPU_STATE_STANDBY)
                        break;
-               rc = sclp_cpu_configure(pcpu->address);
+               rc = sclp_cpu_configure(pcpu->address >> smp_cpu_mt_shift);
                if (rc)
                        break;
-               pcpu->state = CPU_STATE_CONFIGURED;
-               smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
+               for (i = 0; i <= smp_cpu_mtid; i++) {
+                       if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i))
+                               continue;
+                       pcpu[i].state = CPU_STATE_CONFIGURED;
+                       smp_cpu_set_polarization(cpu + i,
+                                                POLARIZATION_UNKNOWN);
+               }
                topology_expect_change();
                break;
        default:
index 811f542b8ed4adc3e209924e57c618e2d32e923c..85565f1ff4743abbf546d67eb35ff2cb10e09e91 100644 (file)
@@ -194,6 +194,14 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
        seq_printf(m, "LPAR CPUs Reserved:   %d\n", info->cpus_reserved);
        seq_printf(m, "LPAR CPUs Dedicated:  %d\n", info->cpus_dedicated);
        seq_printf(m, "LPAR CPUs Shared:     %d\n", info->cpus_shared);
+       if (info->mt_installed & 0x80) {
+               seq_printf(m, "LPAR CPUs G-MTID:     %d\n",
+                          info->mt_general & 0x1f);
+               seq_printf(m, "LPAR CPUs S-MTID:     %d\n",
+                          info->mt_installed & 0x1f);
+               seq_printf(m, "LPAR CPUs PS-MTID:    %d\n",
+                          info->mt_psmtid & 0x1f);
+       }
 }
 
 static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
index b93bed76ea94026d45c782eebe75c08dfb1a323d..24ee33f1af24228e04686700523819fcb77afdf2 100644 (file)
@@ -59,32 +59,50 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
        return mask;
 }
 
-static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu,
+static cpumask_t cpu_thread_map(unsigned int cpu)
+{
+       cpumask_t mask;
+       int i;
+
+       cpumask_copy(&mask, cpumask_of(cpu));
+       if (!topology_enabled || !MACHINE_HAS_TOPOLOGY)
+               return mask;
+       cpu -= cpu % (smp_cpu_mtid + 1);
+       for (i = 0; i <= smp_cpu_mtid; i++)
+               if (cpu_present(cpu + i))
+                       cpumask_set_cpu(cpu + i, &mask);
+       return mask;
+}
+
+static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core,
                                          struct mask_info *book,
                                          struct mask_info *socket,
                                          int one_socket_per_cpu)
 {
-       unsigned int cpu;
+       unsigned int core;
 
-       for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) {
-               unsigned int rcpu;
-               int lcpu;
+       for_each_set_bit(core, &tl_core->mask[0], TOPOLOGY_CORE_BITS) {
+               unsigned int rcore;
+               int lcpu, i;
 
-               rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
-               lcpu = smp_find_processor_id(rcpu);
+               rcore = TOPOLOGY_CORE_BITS - 1 - core + tl_core->origin;
+               lcpu = smp_find_processor_id(rcore << smp_cpu_mt_shift);
                if (lcpu < 0)
                        continue;
-               cpumask_set_cpu(lcpu, &book->mask);
-               cpu_topology[lcpu].book_id = book->id;
-               cpumask_set_cpu(lcpu, &socket->mask);
-               cpu_topology[lcpu].core_id = rcpu;
-               if (one_socket_per_cpu) {
-                       cpu_topology[lcpu].socket_id = rcpu;
-                       socket = socket->next;
-               } else {
-                       cpu_topology[lcpu].socket_id = socket->id;
+               for (i = 0; i <= smp_cpu_mtid; i++) {
+                       cpu_topology[lcpu + i].book_id = book->id;
+                       cpu_topology[lcpu + i].core_id = rcore;
+                       cpu_topology[lcpu + i].thread_id = lcpu + i;
+                       cpumask_set_cpu(lcpu + i, &book->mask);
+                       cpumask_set_cpu(lcpu + i, &socket->mask);
+                       if (one_socket_per_cpu)
+                               cpu_topology[lcpu + i].socket_id = rcore;
+                       else
+                               cpu_topology[lcpu + i].socket_id = socket->id;
+                       smp_cpu_set_polarization(lcpu + i, tl_core->pp);
                }
-               smp_cpu_set_polarization(lcpu, tl_cpu->pp);
+               if (one_socket_per_cpu)
+                       socket = socket->next;
        }
        return socket;
 }
@@ -108,7 +126,7 @@ static void clear_masks(void)
 static union topology_entry *next_tle(union topology_entry *tle)
 {
        if (!tle->nl)
-               return (union topology_entry *)((struct topology_cpu *)tle + 1);
+               return (union topology_entry *)((struct topology_core *)tle + 1);
        return (union topology_entry *)((struct topology_container *)tle + 1);
 }
 
@@ -231,9 +249,11 @@ static void update_cpu_masks(void)
 
        spin_lock_irqsave(&topology_lock, flags);
        for_each_possible_cpu(cpu) {
+               cpu_topology[cpu].thread_mask = cpu_thread_map(cpu);
                cpu_topology[cpu].core_mask = cpu_group_map(&socket_info, cpu);
                cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu);
                if (!MACHINE_HAS_TOPOLOGY) {
+                       cpu_topology[cpu].thread_id = cpu;
                        cpu_topology[cpu].core_id = cpu;
                        cpu_topology[cpu].socket_id = cpu;
                        cpu_topology[cpu].book_id = cpu;
@@ -445,6 +465,12 @@ int topology_cpu_init(struct cpu *cpu)
        return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group);
 }
 
+const struct cpumask *cpu_thread_mask(int cpu)
+{
+       return &cpu_topology[cpu].thread_mask;
+}
+
+
 const struct cpumask *cpu_coregroup_mask(int cpu)
 {
        return &cpu_topology[cpu].core_mask;
@@ -456,6 +482,7 @@ static const struct cpumask *cpu_book_mask(int cpu)
 }
 
 static struct sched_domain_topology_level s390_topology[] = {
+       { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
        { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
        { cpu_book_mask, SD_INIT_NAME(BOOK) },
        { cpu_cpu_mask, SD_INIT_NAME(DIE) },
index e34122e539a16bad4e5727f881f982e4829cd8f0..e53d3595a7c8c1a54400d5fb3e984004cd864219 100644 (file)
@@ -15,6 +15,8 @@
 #include <asm/cputime.h>
 #include <asm/vtimer.h>
 #include <asm/vtime.h>
+#include <asm/cpu_mf.h>
+#include <asm/smp.h>
 
 static void virt_timer_expire(void);
 
@@ -23,6 +25,10 @@ static DEFINE_SPINLOCK(virt_timer_lock);
 static atomic64_t virt_timer_current;
 static atomic64_t virt_timer_elapsed;
 
+static DEFINE_PER_CPU(u64, mt_cycles[32]);
+static DEFINE_PER_CPU(u64, mt_scaling_mult) = { 1 };
+static DEFINE_PER_CPU(u64, mt_scaling_div) = { 1 };
+
 static inline u64 get_vtimer(void)
 {
        u64 timer;
@@ -61,6 +67,8 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
 {
        struct thread_info *ti = task_thread_info(tsk);
        u64 timer, clock, user, system, steal;
+       u64 user_scaled, system_scaled;
+       int i;
 
        timer = S390_lowcore.last_update_timer;
        clock = S390_lowcore.last_update_clock;
@@ -76,15 +84,49 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
        S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
        S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock;
 
+       /* Do MT utilization calculation */
+       if (smp_cpu_mtid) {
+               u64 cycles_new[32], *cycles_old;
+               u64 delta, mult, div;
+
+               cycles_old = this_cpu_ptr(mt_cycles);
+               if (stcctm5(smp_cpu_mtid + 1, cycles_new) < 2) {
+                       mult = div = 0;
+                       for (i = 0; i <= smp_cpu_mtid; i++) {
+                               delta = cycles_new[i] - cycles_old[i];
+                               mult += delta;
+                               div += (i + 1) * delta;
+                       }
+                       if (mult > 0) {
+                               /* Update scaling factor */
+                               __this_cpu_write(mt_scaling_mult, mult);
+                               __this_cpu_write(mt_scaling_div, div);
+                               memcpy(cycles_old, cycles_new,
+                                      sizeof(u64) * (smp_cpu_mtid + 1));
+                       }
+               }
+       }
+
        user = S390_lowcore.user_timer - ti->user_timer;
        S390_lowcore.steal_timer -= user;
        ti->user_timer = S390_lowcore.user_timer;
-       account_user_time(tsk, user, user);
 
        system = S390_lowcore.system_timer - ti->system_timer;
        S390_lowcore.steal_timer -= system;
        ti->system_timer = S390_lowcore.system_timer;
-       account_system_time(tsk, hardirq_offset, system, system);
+
+       user_scaled = user;
+       system_scaled = system;
+       /* Do MT utilization scaling */
+       if (smp_cpu_mtid) {
+               u64 mult = __this_cpu_read(mt_scaling_mult);
+               u64 div = __this_cpu_read(mt_scaling_div);
+
+               user_scaled = (user_scaled * mult) / div;
+               system_scaled = (system_scaled * mult) / div;
+       }
+       account_user_time(tsk, user, user_scaled);
+       account_system_time(tsk, hardirq_offset, system, system_scaled);
 
        steal = S390_lowcore.steal_timer;
        if ((s64) steal > 0) {
@@ -126,7 +168,7 @@ void vtime_account_user(struct task_struct *tsk)
 void vtime_account_irq_enter(struct task_struct *tsk)
 {
        struct thread_info *ti = task_thread_info(tsk);
-       u64 timer, system;
+       u64 timer, system, system_scaled;
 
        timer = S390_lowcore.last_update_timer;
        S390_lowcore.last_update_timer = get_vtimer();
@@ -135,7 +177,15 @@ void vtime_account_irq_enter(struct task_struct *tsk)
        system = S390_lowcore.system_timer - ti->system_timer;
        S390_lowcore.steal_timer -= system;
        ti->system_timer = S390_lowcore.system_timer;
-       account_system_time(tsk, 0, system, system);
+       system_scaled = system;
+       /* Do MT utilization scaling */
+       if (smp_cpu_mtid) {
+               u64 mult = __this_cpu_read(mt_scaling_mult);
+               u64 div = __this_cpu_read(mt_scaling_div);
+
+               system_scaled = (system_scaled * mult) / div;
+       }
+       account_system_time(tsk, 0, system, system_scaled);
 
        virt_timer_forward(system);
 }
index 034a35a3e9c11a0a5a9b7f2d73ba16cf9adbd314..d6c9991f77975e430f738bbbb802ae5e221ab46d 100644 (file)
 #include <linux/smp.h>
 #include <asm/io.h>
 
-int spin_retry = 1000;
+int spin_retry = -1;
+
+static int __init spin_retry_init(void)
+{
+       if (spin_retry < 0)
+               spin_retry = MACHINE_HAS_CAD ? 10 : 1000;
+       return 0;
+}
+early_initcall(spin_retry_init);
 
 /**
  * spin_retry= parameter
@@ -24,6 +32,11 @@ static int __init spin_retry_setup(char *str)
 }
 __setup("spin_retry=", spin_retry_setup);
 
+static inline void _raw_compare_and_delay(unsigned int *lock, unsigned int old)
+{
+       asm(".insn rsy,0xeb0000000022,%0,0,%1" : : "d" (old), "Q" (*lock));
+}
+
 void arch_spin_lock_wait(arch_spinlock_t *lp)
 {
        unsigned int cpu = SPINLOCK_LOCKVAL;
@@ -46,6 +59,8 @@ void arch_spin_lock_wait(arch_spinlock_t *lp)
                /* Loop for a while on the lock value. */
                count = spin_retry;
                do {
+                       if (MACHINE_HAS_CAD)
+                               _raw_compare_and_delay(&lp->lock, owner);
                        owner = ACCESS_ONCE(lp->lock);
                } while (owner && count-- > 0);
                if (!owner)
@@ -84,6 +99,8 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
                /* Loop for a while on the lock value. */
                count = spin_retry;
                do {
+                       if (MACHINE_HAS_CAD)
+                               _raw_compare_and_delay(&lp->lock, owner);
                        owner = ACCESS_ONCE(lp->lock);
                } while (owner && count-- > 0);
                if (!owner)
@@ -100,11 +117,19 @@ EXPORT_SYMBOL(arch_spin_lock_wait_flags);
 
 int arch_spin_trylock_retry(arch_spinlock_t *lp)
 {
+       unsigned int cpu = SPINLOCK_LOCKVAL;
+       unsigned int owner;
        int count;
 
-       for (count = spin_retry; count > 0; count--)
-               if (arch_spin_trylock_once(lp))
-                       return 1;
+       for (count = spin_retry; count > 0; count--) {
+               owner = ACCESS_ONCE(lp->lock);
+               /* Try to get the lock if it is free. */
+               if (!owner) {
+                       if (_raw_compare_and_swap(&lp->lock, 0, cpu))
+                               return 1;
+               } else if (MACHINE_HAS_CAD)
+                       _raw_compare_and_delay(&lp->lock, owner);
+       }
        return 0;
 }
 EXPORT_SYMBOL(arch_spin_trylock_retry);
@@ -126,8 +151,11 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
                }
                old = ACCESS_ONCE(rw->lock);
                owner = ACCESS_ONCE(rw->owner);
-               if ((int) old < 0)
+               if ((int) old < 0) {
+                       if (MACHINE_HAS_CAD)
+                               _raw_compare_and_delay(&rw->lock, old);
                        continue;
+               }
                if (_raw_compare_and_swap(&rw->lock, old, old + 1))
                        return;
        }
@@ -141,8 +169,11 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw)
 
        while (count-- > 0) {
                old = ACCESS_ONCE(rw->lock);
-               if ((int) old < 0)
+               if ((int) old < 0) {
+                       if (MACHINE_HAS_CAD)
+                               _raw_compare_and_delay(&rw->lock, old);
                        continue;
+               }
                if (_raw_compare_and_swap(&rw->lock, old, old + 1))
                        return 1;
        }
@@ -173,6 +204,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev)
                }
                if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
                        break;
+               if (MACHINE_HAS_CAD)
+                       _raw_compare_and_delay(&rw->lock, old);
        }
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
@@ -201,6 +234,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw)
                        smp_rmb();
                if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
                        break;
+               if (MACHINE_HAS_CAD)
+                       _raw_compare_and_delay(&rw->lock, old);
        }
 }
 EXPORT_SYMBOL(_raw_write_lock_wait);
@@ -214,8 +249,11 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw)
 
        while (count-- > 0) {
                old = ACCESS_ONCE(rw->lock);
-               if (old)
+               if (old) {
+                       if (MACHINE_HAS_CAD)
+                               _raw_compare_and_delay(&rw->lock, old);
                        continue;
+               }
                if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
                        return 1;
        }
index 9065d5aa3932dd7f6637069e493f2ad4a3ad72f3..3ff86533f7db925b575309d63b08727551ac0d40 100644 (file)
@@ -171,7 +171,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address)
                table = table + ((address >> 20) & 0x7ff);
                if (bad_address(table))
                        goto bad;
-               pr_cont(KERN_CONT "S:%016lx ", *table);
+               pr_cont("S:%016lx ", *table);
                if (*table & (_SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_LARGE))
                        goto out;
                table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
@@ -261,7 +261,7 @@ static inline void report_user_fault(struct pt_regs *regs, long signr)
                return;
        if (!printk_ratelimit())
                return;
-       printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d",
+       printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d ",
               regs->int_code & 0xffff, regs->int_code >> 17);
        print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN);
        printk(KERN_CONT "\n");
index c7235e01fd674999cc89920be9d03461b7cd4d13..d35b15113b17fd99cc910b8afdad74cb773ecb90 100644 (file)
@@ -71,13 +71,16 @@ static void __init setup_zero_pages(void)
                break;
        case 0x2827:    /* zEC12 */
        case 0x2828:    /* zEC12 */
-       default:
                order = 5;
                break;
+       case 0x2964:    /* z13 */
+       default:
+               order = 7;
+               break;
        }
        /* Limit number of empty zero pages for small memory sizes */
-       if (order > 2 && totalram_pages <= 16384)
-               order = 2;
+       while (order > 2 && (totalram_pages >> 10) < (1UL << order))
+               order--;
 
        empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!empty_zero_page)
index 9b436c21195ec6b16465bb6e1964e2ad343b8321..d008f638b2cd27f7615c11a02bb5d2a8f3138d04 100644 (file)
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/compat.h>
+#include <linux/security.h>
 #include <asm/pgalloc.h>
 
+unsigned long mmap_rnd_mask;
+unsigned long mmap_align_mask;
+
 static unsigned long stack_maxrandom_size(void)
 {
        if (!(current->flags & PF_RANDOMIZE))
@@ -60,8 +64,10 @@ static unsigned long mmap_rnd(void)
 {
        if (!(current->flags & PF_RANDOMIZE))
                return 0;
-       /* 8MB randomization for mmap_base */
-       return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+       if (is_32bit_task())
+               return (get_random_int() & 0x7ff) << PAGE_SHIFT;
+       else
+               return (get_random_int() & mmap_rnd_mask) << PAGE_SHIFT;
 }
 
 static unsigned long mmap_base_legacy(void)
@@ -81,6 +87,106 @@ static inline unsigned long mmap_base(void)
        return STACK_TOP - stack_maxrandom_size() - mmap_rnd() - gap;
 }
 
+unsigned long
+arch_get_unmapped_area(struct file *filp, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       struct vm_unmapped_area_info info;
+       int do_color_align;
+
+       if (len > TASK_SIZE - mmap_min_addr)
+               return -ENOMEM;
+
+       if (flags & MAP_FIXED)
+               return addr;
+
+       if (addr) {
+               addr = PAGE_ALIGN(addr);
+               vma = find_vma(mm, addr);
+               if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
+                   (!vma || addr + len <= vma->vm_start))
+                       return addr;
+       }
+
+       do_color_align = 0;
+       if (filp || (flags & MAP_SHARED))
+               do_color_align = !is_32bit_task();
+
+       info.flags = 0;
+       info.length = len;
+       info.low_limit = mm->mmap_base;
+       info.high_limit = TASK_SIZE;
+       info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+       info.align_offset = pgoff << PAGE_SHIFT;
+       return vm_unmapped_area(&info);
+}
+
+unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+                         const unsigned long len, const unsigned long pgoff,
+                         const unsigned long flags)
+{
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       unsigned long addr = addr0;
+       struct vm_unmapped_area_info info;
+       int do_color_align;
+
+       /* requested length too big for entire address space */
+       if (len > TASK_SIZE - mmap_min_addr)
+               return -ENOMEM;
+
+       if (flags & MAP_FIXED)
+               return addr;
+
+       /* requesting a specific address */
+       if (addr) {
+               addr = PAGE_ALIGN(addr);
+               vma = find_vma(mm, addr);
+               if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
+                               (!vma || addr + len <= vma->vm_start))
+                       return addr;
+       }
+
+       do_color_align = 0;
+       if (filp || (flags & MAP_SHARED))
+               do_color_align = !is_32bit_task();
+
+       info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+       info.length = len;
+       info.low_limit = max(PAGE_SIZE, mmap_min_addr);
+       info.high_limit = mm->mmap_base;
+       info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+       info.align_offset = pgoff << PAGE_SHIFT;
+       addr = vm_unmapped_area(&info);
+
+       /*
+        * A failed mmap() very likely causes application failure,
+        * so fall back to the bottom-up function here. This scenario
+        * can happen with large stack limits and large mmap()
+        * allocations.
+        */
+       if (addr & ~PAGE_MASK) {
+               VM_BUG_ON(addr != -ENOMEM);
+               info.flags = 0;
+               info.low_limit = TASK_UNMAPPED_BASE;
+               info.high_limit = TASK_SIZE;
+               addr = vm_unmapped_area(&info);
+       }
+
+       return addr;
+}
+
+unsigned long randomize_et_dyn(void)
+{
+       unsigned long base;
+
+       base = (STACK_TOP / 3 * 2) & (~mmap_align_mask << PAGE_SHIFT);
+       return base + mmap_rnd();
+}
+
 #ifndef CONFIG_64BIT
 
 /*
@@ -177,4 +283,36 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        }
 }
 
+static int __init setup_mmap_rnd(void)
+{
+       struct cpuid cpu_id;
+
+       get_cpu_id(&cpu_id);
+       switch (cpu_id.machine) {
+       case 0x9672:
+       case 0x2064:
+       case 0x2066:
+       case 0x2084:
+       case 0x2086:
+       case 0x2094:
+       case 0x2096:
+       case 0x2097:
+       case 0x2098:
+       case 0x2817:
+       case 0x2818:
+       case 0x2827:
+       case 0x2828:
+               mmap_rnd_mask = 0x7ffUL;
+               mmap_align_mask = 0UL;
+               break;
+       case 0x2964:    /* z13 */
+       default:
+               mmap_rnd_mask = 0x3ff80UL;
+               mmap_align_mask = 0x7fUL;
+               break;
+       }
+       return 0;
+}
+early_initcall(setup_mmap_rnd);
+
 #endif
index 3cf8cc03fff60d7a59e7b23f4e92d477061a5f42..b2c1542f2ba2ce979befff85f4fc1f9fffeb70ad 100644 (file)
@@ -527,7 +527,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
                table += (gaddr >> 53) & 0x7ff;
                if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY,
-                                    gaddr & 0xffe0000000000000))
+                                    gaddr & 0xffe0000000000000UL))
                        return -ENOMEM;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        }
@@ -535,7 +535,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
                table += (gaddr >> 42) & 0x7ff;
                if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY,
-                                    gaddr & 0xfffffc0000000000))
+                                    gaddr & 0xfffffc0000000000UL))
                        return -ENOMEM;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        }
@@ -543,7 +543,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
                table += (gaddr >> 31) & 0x7ff;
                if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY,
-                                    gaddr & 0xffffffff80000000))
+                                    gaddr & 0xffffffff80000000UL))
                        return -ENOMEM;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        }
index 62c5ea6d8682a51e0c7b006bd623cabe5842b259..8aa271b3d1ad95b79cb0fa40d130ab76d26fc2bd 100644 (file)
@@ -55,7 +55,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
        ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
        if (ret)
                goto out;
-       io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
+       io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 
        ret = -EFAULT;
        if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
@@ -96,7 +96,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
        ret = get_pfn(mmio_addr, VM_READ, &pfn);
        if (ret)
                goto out;
-       io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
+       io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 
        ret = -EFAULT;
        if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
index 4abf11965484b1e17efef10e44f650293687d816..be34ef41b7c741ff67e22158aed702580cb2877c 100644 (file)
@@ -674,8 +674,9 @@ EXPORT_SYMBOL(dasd_enable_device);
 unsigned int dasd_global_profile_level = DASD_PROFILE_OFF;
 
 #ifdef CONFIG_DASD_PROFILE
-struct dasd_profile_info dasd_global_profile_data;
-static struct dentry *dasd_global_profile_dentry;
+struct dasd_profile dasd_global_profile = {
+       .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock),
+};
 static struct dentry *dasd_debugfs_global_entry;
 
 /*
@@ -696,11 +697,13 @@ static void dasd_profile_start(struct dasd_block *block,
                        if (++counter >= 31)
                                break;
 
-       if (dasd_global_profile_level) {
-               dasd_global_profile_data.dasd_io_nr_req[counter]++;
+       spin_lock(&dasd_global_profile.lock);
+       if (dasd_global_profile.data) {
+               dasd_global_profile.data->dasd_io_nr_req[counter]++;
                if (rq_data_dir(req) == READ)
-                       dasd_global_profile_data.dasd_read_nr_req[counter]++;
+                       dasd_global_profile.data->dasd_read_nr_req[counter]++;
        }
+       spin_unlock(&dasd_global_profile.lock);
 
        spin_lock(&block->profile.lock);
        if (block->profile.data) {
@@ -825,8 +828,9 @@ static void dasd_profile_end(struct dasd_block *block,
        dasd_profile_counter(irqtime / sectors, irqtimeps_ind);
        dasd_profile_counter(endtime, endtime_ind);
 
-       if (dasd_global_profile_level) {
-               dasd_profile_end_add_data(&dasd_global_profile_data,
+       spin_lock(&dasd_global_profile.lock);
+       if (dasd_global_profile.data) {
+               dasd_profile_end_add_data(dasd_global_profile.data,
                                          cqr->startdev != block->base,
                                          cqr->cpmode == 1,
                                          rq_data_dir(req) == READ,
@@ -835,6 +839,7 @@ static void dasd_profile_end(struct dasd_block *block,
                                          irqtime_ind, irqtimeps_ind,
                                          endtime_ind);
        }
+       spin_unlock(&dasd_global_profile.lock);
 
        spin_lock(&block->profile.lock);
        if (block->profile.data)
@@ -876,12 +881,6 @@ void dasd_profile_reset(struct dasd_profile *profile)
        spin_unlock_bh(&profile->lock);
 }
 
-void dasd_global_profile_reset(void)
-{
-       memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data));
-       getnstimeofday(&dasd_global_profile_data.starttod);
-}
-
 int dasd_profile_on(struct dasd_profile *profile)
 {
        struct dasd_profile_info *data;
@@ -949,12 +948,20 @@ static ssize_t dasd_stats_write(struct file *file,
                dasd_profile_reset(prof);
        } else if (strncmp(str, "on", 2) == 0) {
                rc = dasd_profile_on(prof);
-               if (!rc)
-                       rc = user_len;
+               if (rc)
+                       goto out;
+               rc = user_len;
+               if (prof == &dasd_global_profile) {
+                       dasd_profile_reset(prof);
+                       dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
+               }
        } else if (strncmp(str, "off", 3) == 0) {
+               if (prof == &dasd_global_profile)
+                       dasd_global_profile_level = DASD_PROFILE_OFF;
                dasd_profile_off(prof);
        } else
                rc = -EINVAL;
+out:
        vfree(buffer);
        return rc;
 }
@@ -1044,57 +1051,6 @@ static const struct file_operations dasd_stats_raw_fops = {
        .write          = dasd_stats_write,
 };
 
-static ssize_t dasd_stats_global_write(struct file *file,
-                                      const char __user *user_buf,
-                                      size_t user_len, loff_t *pos)
-{
-       char *buffer, *str;
-       ssize_t rc;
-
-       if (user_len > 65536)
-               user_len = 65536;
-       buffer = dasd_get_user_string(user_buf, user_len);
-       if (IS_ERR(buffer))
-               return PTR_ERR(buffer);
-       str = skip_spaces(buffer);
-       rc = user_len;
-       if (strncmp(str, "reset", 5) == 0) {
-               dasd_global_profile_reset();
-       } else if (strncmp(str, "on", 2) == 0) {
-               dasd_global_profile_reset();
-               dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
-       } else if (strncmp(str, "off", 3) == 0) {
-               dasd_global_profile_level = DASD_PROFILE_OFF;
-       } else
-               rc = -EINVAL;
-       vfree(buffer);
-       return rc;
-}
-
-static int dasd_stats_global_show(struct seq_file *m, void *v)
-{
-       if (!dasd_global_profile_level) {
-               seq_puts(m, "disabled\n");
-               return 0;
-       }
-       dasd_stats_seq_print(m, &dasd_global_profile_data);
-       return 0;
-}
-
-static int dasd_stats_global_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, dasd_stats_global_show, NULL);
-}
-
-static const struct file_operations dasd_stats_global_fops = {
-       .owner          = THIS_MODULE,
-       .open           = dasd_stats_global_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = dasd_stats_global_write,
-};
-
 static void dasd_profile_init(struct dasd_profile *profile,
                              struct dentry *base_dentry)
 {
@@ -1123,20 +1079,16 @@ static void dasd_profile_exit(struct dasd_profile *profile)
 static void dasd_statistics_removeroot(void)
 {
        dasd_global_profile_level = DASD_PROFILE_OFF;
-       debugfs_remove(dasd_global_profile_dentry);
-       dasd_global_profile_dentry = NULL;
+       dasd_profile_exit(&dasd_global_profile);
        debugfs_remove(dasd_debugfs_global_entry);
        debugfs_remove(dasd_debugfs_root_entry);
 }
 
 static void dasd_statistics_createroot(void)
 {
-       umode_t mode;
        struct dentry *pde;
 
        dasd_debugfs_root_entry = NULL;
-       dasd_debugfs_global_entry = NULL;
-       dasd_global_profile_dentry = NULL;
        pde = debugfs_create_dir("dasd", NULL);
        if (!pde || IS_ERR(pde))
                goto error;
@@ -1145,13 +1097,7 @@ static void dasd_statistics_createroot(void)
        if (!pde || IS_ERR(pde))
                goto error;
        dasd_debugfs_global_entry = pde;
-
-       mode = (S_IRUSR | S_IWUSR | S_IFREG);
-       pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry,
-                                 NULL, &dasd_stats_global_fops);
-       if (!pde || IS_ERR(pde))
-               goto error;
-       dasd_global_profile_dentry = pde;
+       dasd_profile_init(&dasd_global_profile, dasd_debugfs_global_entry);
        return;
 
 error:
index 8b5d4100abf7c75107b61ce02ed7e7d10c252f81..227e3dea3155268e7d060b07937bb7ac6d340732 100644 (file)
@@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize)
 #define DASD_PROFILE_GLOBAL_ONLY 2
 
 extern debug_info_t *dasd_debug_area;
-extern struct dasd_profile_info dasd_global_profile_data;
+extern struct dasd_profile dasd_global_profile;
 extern unsigned int dasd_global_profile_level;
 extern const struct block_device_operations dasd_device_operations;
 
@@ -728,7 +728,6 @@ int dasd_device_is_ro(struct dasd_device *);
 void dasd_profile_reset(struct dasd_profile *);
 int dasd_profile_on(struct dasd_profile *);
 void dasd_profile_off(struct dasd_profile *);
-void dasd_global_profile_reset(void);
 char *dasd_get_user_string(const char __user *, size_t);
 
 /* externals in dasd_devmap.c */
index 78ac905a5b7f18c046e121ebc41f1e7f37cc84f6..aa7bb2d1da81154940b7755c69f6744fb710cb15 100644 (file)
@@ -212,14 +212,15 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
        struct dasd_profile_info *prof;
        int factor;
 
-       /* check for active profiling */
-       if (!dasd_global_profile_level) {
+       spin_lock_bh(&dasd_global_profile.lock);
+       prof = dasd_global_profile.data;
+       if (!prof) {
+               spin_unlock_bh(&dasd_global_profile.lock);
                seq_printf(m, "Statistics are off - they might be "
                                    "switched on using 'echo set on > "
                                    "/proc/dasd/statistics'\n");
                return 0;
        }
-       prof = &dasd_global_profile_data;
 
        /* prevent counter 'overflow' on output */
        for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
@@ -255,6 +256,7 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
        dasd_statistics_array(m, prof->dasd_io_time3, factor);
        seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
        dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
+       spin_unlock_bh(&dasd_global_profile.lock);
 #else
        seq_printf(m, "Statistics are not activated in this kernel\n");
 #endif
@@ -291,14 +293,19 @@ static ssize_t dasd_stats_proc_write(struct file *file,
                                dasd_stats_all_block_off();
                                goto out_error;
                        }
-                       dasd_global_profile_reset();
+                       rc = dasd_profile_on(&dasd_global_profile);
+                       if (rc) {
+                               dasd_stats_all_block_off();
+                               goto out_error;
+                       }
+                       dasd_profile_reset(&dasd_global_profile);
                        dasd_global_profile_level = DASD_PROFILE_ON;
                        pr_info("The statistics feature has been switched "
                                "on\n");
                } else if (strcmp(str, "off") == 0) {
-                       /* switch off and reset statistics profiling */
+                       /* switch off statistics profiling */
                        dasd_global_profile_level = DASD_PROFILE_OFF;
-                       dasd_global_profile_reset();
+                       dasd_profile_off(&dasd_global_profile);
                        dasd_stats_all_block_off();
                        pr_info("The statistics feature has been switched "
                                "off\n");
@@ -306,7 +313,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
                        goto out_parse_error;
        } else if (strncmp(str, "reset", 5) == 0) {
                /* reset the statistics */
-               dasd_global_profile_reset();
+               dasd_profile_reset(&dasd_global_profile);
                dasd_stats_all_block_reset();
                pr_info("The statistics have been reset\n");
        } else
index b550c8c8d0103e052689d125e3daacea2f30d993..7f900229404dfd722c846c379b67d4b982d414d8 100644 (file)
@@ -438,7 +438,13 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
                        pr_info("All DCSSs that map to device %s are "
                                "saved\n", dev_info->segment_name);
                        list_for_each_entry(entry, &dev_info->seg_list, lh) {
-                               segment_save(entry->segment_name);
+                               if (entry->segment_type == SEG_TYPE_EN ||
+                                   entry->segment_type == SEG_TYPE_SN)
+                                       pr_warn("DCSS %s is of type SN or EN"
+                                               " and cannot be saved\n",
+                                               entry->segment_name);
+                               else
+                                       segment_save(entry->segment_name);
                        }
                }  else {
                        // device is busy => we save it when it becomes
@@ -797,7 +803,12 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
                pr_info("Device %s has become idle and is being saved "
                        "now\n", dev_info->segment_name);
                list_for_each_entry(entry, &dev_info->seg_list, lh) {
-                       segment_save(entry->segment_name);
+                       if (entry->segment_type == SEG_TYPE_EN ||
+                           entry->segment_type == SEG_TYPE_SN)
+                               pr_warn("DCSS %s is of type SN or EN and cannot"
+                                       " be saved\n", entry->segment_name);
+                       else
+                               segment_save(entry->segment_name);
                }
                dev_info->save_pending = 0;
        }
index 4bd63322fc29e67987a2fd56afe8b73243ced37a..d4b61d9088fb731f504b83fb7aeb9b9ccc1b6fe5 100644 (file)
@@ -200,10 +200,9 @@ int hmcdrv_ftp_probe(void)
        rc = hmcdrv_ftp_startup();
 
        if (rc)
-               return rc;
+               goto out;
 
        rc = hmcdrv_ftp_do(&ftp);
-       free_page((unsigned long) ftp.buf);
        hmcdrv_ftp_shutdown();
 
        switch (rc) {
@@ -216,7 +215,8 @@ int hmcdrv_ftp_probe(void)
                        rc = 0; /* clear length (success) */
                break;
        } /* switch */
-
+out:
+       free_page((unsigned long) ftp.buf);
        return rc;
 }
 EXPORT_SYMBOL(hmcdrv_ftp_probe);
index 505c6a78ee1a639e3fd8905dac434cd5a7fcef64..251a318a9b7541452c0142f0f0f8ce84167b8dc2 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/stat.h>
 
 #include "hmcdrv_ftp.h"
index 5bd6cb145a87d4bfd4e11f7ca139bac1f7ec51e3..daf6cd5079ec3e0052c64ba24f2ce1f5ea9f623d 100644 (file)
@@ -20,26 +20,31 @@ struct read_info_sccb {
        struct  sccb_header header;     /* 0-7 */
        u16     rnmax;                  /* 8-9 */
        u8      rnsize;                 /* 10 */
-       u8      _reserved0[16 - 11];    /* 11-15 */
+       u8      _pad_11[16 - 11];       /* 11-15 */
        u16     ncpurl;                 /* 16-17 */
        u16     cpuoff;                 /* 18-19 */
-       u8      _reserved7[24 - 20];    /* 20-23 */
+       u8      _pad_20[24 - 20];       /* 20-23 */
        u8      loadparm[8];            /* 24-31 */
-       u8      _reserved1[48 - 32];    /* 32-47 */
+       u8      _pad_32[42 - 32];       /* 32-41 */
+       u8      fac42;                  /* 42 */
+       u8      fac43;                  /* 43 */
+       u8      _pad_44[48 - 44];       /* 44-47 */
        u64     facilities;             /* 48-55 */
-       u8      _reserved2a[76 - 56];   /* 56-75 */
+       u8      _pad_56[66 - 56];       /* 56-65 */
+       u8      fac66;                  /* 66 */
+       u8      _pad_67[76 - 67];       /* 67-83 */
        u32     ibc;                    /* 76-79 */
-       u8      _reserved2b[84 - 80];   /* 80-83 */
+       u8      _pad80[84 - 80];        /* 80-83 */
        u8      fac84;                  /* 84 */
        u8      fac85;                  /* 85 */
-       u8      _reserved3[91 - 86];    /* 86-90 */
+       u8      _pad_86[91 - 86];       /* 86-90 */
        u8      flags;                  /* 91 */
-       u8      _reserved4[100 - 92];   /* 92-99 */
+       u8      _pad_92[100 - 92];      /* 92-99 */
        u32     rnsize2;                /* 100-103 */
        u64     rnmax2;                 /* 104-111 */
-       u8      _reserved5[120 - 112];  /* 112-119 */
+       u8      _pad_112[120 - 112];    /* 112-119 */
        u16     hcpua;                  /* 120-121 */
-       u8      _reserved6[4096 - 122]; /* 122-4095 */
+       u8      _pad_122[4096 - 122];   /* 122-4095 */
 } __packed __aligned(PAGE_SIZE);
 
 static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
@@ -50,6 +55,10 @@ static unsigned int sclp_max_cpu;
 static struct sclp_ipl_info sclp_ipl_info;
 static unsigned char sclp_siif;
 static u32 sclp_ibc;
+static unsigned int sclp_mtid;
+static unsigned int sclp_mtid_cp;
+static unsigned int sclp_mtid_max;
+static unsigned int sclp_mtid_prev;
 
 u64 sclp_facilities;
 u8 sclp_fac84;
@@ -128,7 +137,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        boot_cpu_address = stap();
        cpue = (void *)sccb + sccb->cpuoff;
        for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
-               if (boot_cpu_address != cpue->address)
+               if (boot_cpu_address != cpue->core_id)
                        continue;
                sclp_siif = cpue->siif;
                break;
@@ -139,6 +148,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        if (sccb->flags & 0x2)
                sclp_ipl_info.has_dump = 1;
        memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
+
+       sclp_mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
+       sclp_mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
+       sclp_mtid_max = max(sclp_mtid, sclp_mtid_cp);
+       sclp_mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
 }
 
 bool __init sclp_has_linemode(void)
@@ -178,6 +192,21 @@ unsigned int sclp_get_ibc(void)
 }
 EXPORT_SYMBOL(sclp_get_ibc);
 
+unsigned int sclp_get_mtid(u8 cpu_type)
+{
+       return cpu_type ? sclp_mtid : sclp_mtid_cp;
+}
+
+unsigned int sclp_get_mtid_max(void)
+{
+       return sclp_mtid_max;
+}
+
+unsigned int sclp_get_mtid_prev(void)
+{
+       return sclp_mtid_prev;
+}
+
 /*
  * This function will be called after sclp_facilities_detect(), which gets
  * called from early.c code. The sclp_facilities_detect() function retrieves
index 9aa79702b3707a26ef0b4d370c54bf86b51251de..de69f0ddc321dedbb7270ae9fcdf75afe1d148fc 100644 (file)
@@ -773,13 +773,11 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
                        "occurred\n");
                return tape_34xx_erp_failed(request, -EIO);
        case 0x57:
-               if (device->cdev->id.driver_info == tape_3480) {
-                       /* Attention intercept. */
-                       return tape_34xx_erp_retry(request);
-               } else {
-                       /* Global status intercept. */
-                       return tape_34xx_erp_retry(request);
-               }
+               /*
+                * 3480: Attention intercept.
+                * 3490: Global status intercept.
+                */
+               return tape_34xx_erp_retry(request);
        case 0x5a:
                /*
                 * Tape length incompatible. The tape inserted is too long,
index 10eb738fc81a88e4e510be25e7fa69b0f32463df..3578105989a0d724704058df6c83d9ec6ce52f16 100644 (file)
@@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
 {
        struct subchannel_id uninitialized_var(schid);
 
-       s390_reset_system(NULL, NULL);
+       s390_reset_system(NULL, NULL, NULL);
        if (reipl_find_schid(devid, &schid) != 0)
                panic("IPL Device not found\n");
        do_reipl_asm(*((__u32*)&schid));
index 5a999084a229545cdda97c9b9bc6980acf45ea76..b3e06a7b9480f385b1bbd952d30f7d525afc5436 100644 (file)
@@ -38,11 +38,6 @@ void idset_free(struct idset *set)
        vfree(set);
 }
 
-void idset_clear(struct idset *set)
-{
-       memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id));
-}
-
 void idset_fill(struct idset *set)
 {
        memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id));
@@ -103,21 +98,6 @@ int idset_sch_contains(struct idset *set, struct subchannel_id schid)
        return idset_contains(set, schid.ssid, schid.sch_no);
 }
 
-int idset_sch_get_first(struct idset *set, struct subchannel_id *schid)
-{
-       int ssid = 0;
-       int id = 0;
-       int rc;
-
-       rc = idset_get_first(set, &ssid, &id);
-       if (rc) {
-               init_subchannel_id(schid);
-               schid->ssid = ssid;
-               schid->sch_no = id;
-       }
-       return rc;
-}
-
 int idset_is_empty(struct idset *set)
 {
        return bitmap_empty(set->bitmap, set->num_ssid * set->num_id);
index 06d3bc01bb0934a52198349da2657e8787c46c13..22b58104683be867f0f416940001b0fe1e36f8ca 100644 (file)
@@ -11,7 +11,6 @@
 struct idset;
 
 void idset_free(struct idset *set);
-void idset_clear(struct idset *set);
 void idset_fill(struct idset *set);
 
 struct idset *idset_sch_new(void);
@@ -19,7 +18,6 @@ void idset_sch_add(struct idset *set, struct subchannel_id id);
 void idset_sch_del(struct idset *set, struct subchannel_id id);
 void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid);
 int idset_sch_contains(struct idset *set, struct subchannel_id id);
-int idset_sch_get_first(struct idset *set, struct subchannel_id *id);
 int idset_is_empty(struct idset *set);
 void idset_add_set(struct idset *to, struct idset *from);
 
index 4d41bf75c23318577638fa45493aab748e0473a7..3d7f19fb9a4ebda3bc744c6f1bcfcec047c73770 100644 (file)
@@ -203,6 +203,24 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
        return reg1;
 }
 
+/**
+ * ap_query_facilities(): PQAP(TAPQ) query facilities.
+ * @qid: The AP queue number
+ *
+ * Returns content of general register 2 after the PQAP(TAPQ)
+ * instruction was called.
+ */
+static inline unsigned long ap_query_facilities(ap_qid_t qid)
+{
+       register unsigned long reg0 asm ("0") = qid | 0x00800000UL;
+       register unsigned long reg1 asm ("1");
+       register unsigned long reg2 asm ("2") = 0UL;
+
+       asm volatile(".long 0xb2af0000"  /* PQAP(TAPQ) */
+                    : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+       return reg2;
+}
+
 /**
  * ap_reset_queue(): Reset adjunct processor queue.
  * @qid: The AP queue number
@@ -1006,6 +1024,51 @@ void ap_bus_force_rescan(void)
 }
 EXPORT_SYMBOL(ap_bus_force_rescan);
 
+/*
+ * ap_test_config(): helper function to extract the nrth bit
+ *                  within the unsigned int array field.
+ */
+static inline int ap_test_config(unsigned int *field, unsigned int nr)
+{
+       if (nr > 0xFFu)
+               return 0;
+       return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
+}
+
+/*
+ * ap_test_config_card_id(): Test, whether an AP card ID is configured.
+ * @id AP card ID
+ *
+ * Returns 0 if the card is not configured
+ *        1 if the card is configured or
+ *          if the configuration information is not available
+ */
+static inline int ap_test_config_card_id(unsigned int id)
+{
+       if (!ap_configuration)
+               return 1;
+       return ap_test_config(ap_configuration->apm, id);
+}
+
+/*
+ * ap_test_config_domain(): Test, whether an AP usage domain is configured.
+ * @domain AP usage domain ID
+ *
+ * Returns 0 if the usage domain is not configured
+ *        1 if the usage domain is configured or
+ *          if the configuration information is not available
+ */
+static inline int ap_test_config_domain(unsigned int domain)
+{
+       if (!ap_configuration)    /* QCI not supported */
+               if (domain < 16)
+                       return 1; /* then domains 0...15 are configured */
+               else
+                       return 0;
+       else
+               return ap_test_config(ap_configuration->aqm, domain);
+}
+
 /*
  * AP bus attributes.
  */
@@ -1121,6 +1184,42 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
 
 static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store);
 
+static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf)
+{
+       ap_qid_t qid;
+       int i, nd, max_domain_id = -1;
+       unsigned long fbits;
+
+       if (ap_configuration) {
+               if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS) {
+                       for (i = 0; i < AP_DEVICES; i++) {
+                               if (!ap_test_config_card_id(i))
+                                       continue;
+                               qid = AP_MKQID(i, ap_domain_index);
+                               fbits = ap_query_facilities(qid);
+                               if (fbits & (1UL << 57)) {
+                                       /* the N bit is 0, Nd field is filled */
+                                       nd = (int)((fbits & 0x00FF0000UL)>>16);
+                                       if (nd > 0)
+                                               max_domain_id = nd;
+                                       else
+                                               max_domain_id = 15;
+                               } else {
+                                       /* N bit is 1, max 16 domains */
+                                       max_domain_id = 15;
+                               }
+                               break;
+                       }
+               }
+       } else {
+               /* no APXA support, older machines with max 16 domains */
+               max_domain_id = 15;
+       }
+       return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id);
+}
+
+static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL);
+
 static struct bus_attribute *const ap_bus_attrs[] = {
        &bus_attr_ap_domain,
        &bus_attr_ap_control_domain_mask,
@@ -1128,50 +1227,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
        &bus_attr_poll_thread,
        &bus_attr_ap_interrupts,
        &bus_attr_poll_timeout,
+       &bus_attr_ap_max_domain_id,
        NULL,
 };
 
-static inline int ap_test_config(unsigned int *field, unsigned int nr)
-{
-       if (nr > 0xFFu)
-               return 0;
-       return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
-}
-
-/*
- * ap_test_config_card_id(): Test, whether an AP card ID is configured.
- * @id AP card ID
- *
- * Returns 0 if the card is not configured
- *        1 if the card is configured or
- *          if the configuration information is not available
- */
-static inline int ap_test_config_card_id(unsigned int id)
-{
-       if (!ap_configuration)
-               return 1;
-       return ap_test_config(ap_configuration->apm, id);
-}
-
-/*
- * ap_test_config_domain(): Test, whether an AP usage domain is configured.
- * @domain AP usage domain ID
- *
- * Returns 0 if the usage domain is not configured
- *        1 if the usage domain is configured or
- *          if the configuration information is not available
- */
-static inline int ap_test_config_domain(unsigned int domain)
-{
-       if (!ap_configuration)    /* QCI not supported */
-               if (domain < 16)
-                       return 1; /* then domains 0...15 are configured */
-               else
-                       return 0;
-       else
-               return ap_test_config(ap_configuration->aqm, domain);
-}
-
 /**
  * ap_query_configuration(): Query AP configuration information.
  *
@@ -1434,9 +1493,6 @@ static void ap_scan_bus(struct work_struct *unused)
                                continue;
                        }
                        break;
-               case 11:
-                       ap_dev->device_type = 10;
-                       break;
                default:
                        ap_dev->device_type = device_type;
                }
index 055a0f956d171865c2e2c01b121c7ccd4e5198aa..2737d261a32400797e2f58fb8d3a7161cf9a01bc 100644 (file)
@@ -117,6 +117,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
 #define AP_DEVICE_TYPE_CEX3A   8
 #define AP_DEVICE_TYPE_CEX3C   9
 #define AP_DEVICE_TYPE_CEX4    10
+#define AP_DEVICE_TYPE_CEX5    11
 
 /*
  * Known function facilities
index b3d496bfaa7eadd08aa27e15a26c0e177a507685..750876891931627641131a59dfd58df2c4e8f8ce 100644 (file)
@@ -75,6 +75,7 @@ struct ica_z90_status {
 #define ZCRYPT_CEX3C           7
 #define ZCRYPT_CEX3A           8
 #define ZCRYPT_CEX4           10
+#define ZCRYPT_CEX5           11
 
 /**
  * Large random numbers are pulled in 4096 byte chunks from the crypto cards
index 569f8b1d86c05305501530b33d2fdfba84e114a9..71e698b8577286f74fce26c1e069f7cb7193ff30 100644 (file)
 
 #define CEX4A_SPEED_RATING     900      /* TODO new card, new speed rating */
 #define CEX4C_SPEED_RATING     6500     /* TODO new card, new speed rating */
+#define CEX4P_SPEED_RATING     7000     /* TODO new card, new speed rating */
+#define CEX5A_SPEED_RATING     450      /* TODO new card, new speed rating */
+#define CEX5C_SPEED_RATING     3250     /* TODO new card, new speed rating */
+#define CEX5P_SPEED_RATING     3500     /* TODO new card, new speed rating */
 
 #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE
 #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE
@@ -39,6 +43,7 @@
 
 static struct ap_device_id zcrypt_cex4_ids[] = {
        { AP_DEVICE(AP_DEVICE_TYPE_CEX4)  },
+       { AP_DEVICE(AP_DEVICE_TYPE_CEX5)  },
        { /* end of list */ },
 };
 
@@ -70,11 +75,18 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
 
        switch (ap_dev->device_type) {
        case AP_DEVICE_TYPE_CEX4:
+       case AP_DEVICE_TYPE_CEX5:
                if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
                        zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
                        if (!zdev)
                                return -ENOMEM;
-                       zdev->type_string = "CEX4A";
+                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+                               zdev->type_string = "CEX4A";
+                               zdev->speed_rating = CEX4A_SPEED_RATING;
+                       } else {
+                               zdev->type_string = "CEX5A";
+                               zdev->speed_rating = CEX5A_SPEED_RATING;
+                       }
                        zdev->user_space_type = ZCRYPT_CEX3A;
                        zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
                        if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
@@ -90,33 +102,42 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
                                        CEX4A_MAX_MOD_SIZE_2K;
                        }
                        zdev->short_crt = 1;
-                       zdev->speed_rating = CEX4A_SPEED_RATING;
                        zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
                                                           MSGTYPE50_VARIANT_DEFAULT);
                } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
                        zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
                        if (!zdev)
                                return -ENOMEM;
-                       zdev->type_string = "CEX4C";
+                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+                               zdev->type_string = "CEX4C";
+                               zdev->speed_rating = CEX4C_SPEED_RATING;
+                       } else {
+                               zdev->type_string = "CEX5C";
+                               zdev->speed_rating = CEX5C_SPEED_RATING;
+                       }
                        zdev->user_space_type = ZCRYPT_CEX3C;
                        zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
                        zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
                        zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
                        zdev->short_crt = 0;
-                       zdev->speed_rating = CEX4C_SPEED_RATING;
                        zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
                                                           MSGTYPE06_VARIANT_DEFAULT);
                } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
                        zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
                        if (!zdev)
                                return -ENOMEM;
-                       zdev->type_string = "CEX4P";
+                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+                               zdev->type_string = "CEX4P";
+                               zdev->speed_rating = CEX4P_SPEED_RATING;
+                       } else {
+                               zdev->type_string = "CEX5P";
+                               zdev->speed_rating = CEX5P_SPEED_RATING;
+                       }
                        zdev->user_space_type = ZCRYPT_CEX4;
                        zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
                        zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
                        zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
                        zdev->short_crt = 0;
-                       zdev->speed_rating = CEX4C_SPEED_RATING;
                        zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
                                                        MSGTYPE06_VARIANT_EP11);
                }
index ea74460f363862507cbf85af2b2873ae8208ae72..f78a87b07872ffad69234d680953e1236f8dad81 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
+ * z/VM IUCV hypervisor console (HVC) device driver
  *
  * This HVC device driver provides terminal access using
  * z/VM IUCV communication paths.
  *
- * Copyright IBM Corp. 2008, 2009
+ * Copyright IBM Corp. 2008, 2013
  *
  * Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
@@ -102,6 +102,7 @@ static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
 #define IUCV_HVC_CON_IDX       (0)
 /* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
 #define MAX_VMID_FILTER                (500)
+#define FILTER_WILDCARD_CHAR   '*'
 static size_t hvc_iucv_filter_size;
 static void *hvc_iucv_filter;
 static const char *hvc_iucv_filter_string;
@@ -734,20 +735,31 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
  * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID
  * @ipvmid:    Originating z/VM user ID (right padded with blanks)
  *
- * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise
- * non-zero.
+ * Returns 0 if the z/VM user ID that is specified with @ipvmid is permitted to
+ * connect, otherwise non-zero.
  */
 static int hvc_iucv_filter_connreq(u8 ipvmid[8])
 {
-       size_t i;
+       const char *wildcard, *filter_entry;
+       size_t i, len;
 
        /* Note: default policy is ACCEPT if no filter is set */
        if (!hvc_iucv_filter_size)
                return 0;
 
-       for (i = 0; i < hvc_iucv_filter_size; i++)
-               if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8))
+       for (i = 0; i < hvc_iucv_filter_size; i++) {
+               filter_entry = hvc_iucv_filter + (8 * i);
+
+               /* If a filter entry contains the filter wildcard character,
+                * reduce the length to match the leading portion of the user
+                * ID only (wildcard match).  Characters following the wildcard
+                * are ignored.
+                */
+               wildcard = strnchr(filter_entry, 8, FILTER_WILDCARD_CHAR);
+               len = (wildcard) ? wildcard - filter_entry : 8;
+               if (0 == memcmp(ipvmid, filter_entry, len))
                        return 0;
+       }
        return 1;
 }
 
@@ -1166,6 +1178,7 @@ static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
 /**
  * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID
  * @filter:    String containing a comma-separated list of z/VM user IDs
+ * @dest:      Location where to store the parsed z/VM user ID
  */
 static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
 {
@@ -1188,6 +1201,10 @@ static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
        if (filter[len - 1] == '\n')
                len--;
 
+       /* prohibit filter entries containing the wildcard character only */
+       if (len == 1 && *filter == FILTER_WILDCARD_CHAR)
+               return ERR_PTR(-EINVAL);
+
        if (len > 8)
                return ERR_PTR(-EINVAL);
 
index 176bf816875edcb76fe9dd39470c5e1c139a4551..17f624cdf53c5609066389bd3da3375fcdfe2827 100644 (file)
@@ -54,7 +54,11 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 #include <linux/compiler-gcc.h>
 #endif
 
+#ifdef CC_USING_HOTPATCH
+#define notrace __attribute__((hotpatch(0,0)))
+#else
 #define notrace __attribute__((no_instrument_function))
+#endif
 
 /* Intel compiler defines __GNUC__. So we will overwrite implementations
  * coming from above header files here
index 616994f0a76f873c6d5e1c3827d9c07630c7b9ae..07737e50fe6e6ec2c35d8a40794a535e7d4a71b0 100644 (file)
@@ -13,8 +13,8 @@ obj-y     = fork.o exec_domain.o panic.o \
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
-CFLAGS_REMOVE_cgroup-debug.o = -pg
-CFLAGS_REMOVE_irq_work.o = -pg
+CFLAGS_REMOVE_cgroup-debug.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE)
 endif
 
 # cond_syscall is currently not LTO compatible
index 103f5d147b2f9f483b8c3920178d4bdbfb74e400..2925188f50eabe18bd14d2d3752651dcc67b59ef 100644 (file)
@@ -1,5 +1,5 @@
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_core.o = -pg
+CFLAGS_REMOVE_core.o = $(CC_FLAGS_FTRACE)
 endif
 
 obj-y := core.o ring_buffer.o callchain.o
index 4ca8eb1519755ac17e314259fa595d18f76db058..de7a416cca2a79e537ff9fdb489aef09b4c01662 100644 (file)
@@ -2,10 +2,10 @@
 obj-y += mutex.o semaphore.o rwsem.o
 
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_lockdep.o = -pg
-CFLAGS_REMOVE_lockdep_proc.o = -pg
-CFLAGS_REMOVE_mutex-debug.o = -pg
-CFLAGS_REMOVE_rtmutex-debug.o = -pg
+CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_lockdep_proc.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_mutex-debug.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_rtmutex-debug.o = $(CC_FLAGS_FTRACE)
 endif
 
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
index ab32b7b0db5c6b30b4cc64e61e6a857fb51c87e6..46be8702487561cd88a7895fea8c6401d72e9ce6 100644 (file)
@@ -1,5 +1,5 @@
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_clock.o = -pg
+CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE)
 endif
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
index 979ccde26720410592439cf7fe99e28bb3eb0e70..98f26588255ec7ed18a37b71be71ec2d6405afad 100644 (file)
@@ -3,11 +3,11 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
-KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
+KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
 
 ifdef CONFIG_FTRACE_SELFTEST
 # selftest needs instrumentation
-CFLAGS_trace_selftest_dynamic.o = -pg
+CFLAGS_trace_selftest_dynamic.o = $(CC_FLAGS_FTRACE)
 obj-y += trace_selftest_dynamic.o
 endif
 endif
index 7db78934ec07c25cae7d62db863d227da41cd546..25c061f77df7997b3a914525a597026eb1a7670c 100644 (file)
@@ -4,7 +4,7 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
-KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
+KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
 endif
 
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
index 649ce68440331cdd5c5446ac76e01a487d2bcf6a..01df30af4d4a50f7ffec08993115b2e412128d1f 100644 (file)
@@ -234,8 +234,9 @@ sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH
        "$(if $(part-of-module),1,0)" "$(@)";
 recordmcount_source := $(srctree)/scripts/recordmcount.pl
 endif
-cmd_record_mcount =                                            \
-       if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then    \
+cmd_record_mcount =                                            \
+       if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" =   \
+            "$(CC_FLAGS_FTRACE)" ]; then                       \
                $(sub_cmd_record_mcount)                        \
        fi;
 endif
index 537c38ca2e1c7008b2f0f98d4e172c714162eb79..826470d7f00077278875a68c577bccbc7a82d5ea 100755 (executable)
@@ -242,8 +242,13 @@ if ($arch eq "x86_64") {
     $cc .= " -m32";
 
 } elsif ($arch eq "s390" && $bits == 64) {
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
-    $mcount_adjust = -14;
+    if ($cc =~ /-DCC_USING_HOTPATCH/) {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
+       $mcount_adjust = 0;
+    } else {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
+       $mcount_adjust = -14;
+    }
     $alignment = 8;
     $type = ".quad";
     $ld .= " -m elf64_s390";