mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
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 ...
This commit is contained in:
		
						commit
						b3d6524ff7
					
				
					 82 changed files with 1640 additions and 1030 deletions
				
			
		| 
						 | 
					@ -7,8 +7,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Overview of Document:
 | 
					Overview of Document:
 | 
				
			||||||
=====================
 | 
					=====================
 | 
				
			||||||
This document is intended to give a good overview of how to debug
 | 
					This document is intended to give a good overview of how to debug Linux for
 | 
				
			||||||
Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a
 | 
					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
 | 
					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
 | 
					390 IO in any detail. It is intended to complement the documents in the
 | 
				
			||||||
reference section below & any other worthwhile references you get.
 | 
					reference section below & any other worthwhile references you get.
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,6 @@ Examining core dumps
 | 
				
			||||||
ldd
 | 
					ldd
 | 
				
			||||||
Debugging modules
 | 
					Debugging modules
 | 
				
			||||||
The proc file system
 | 
					The proc file system
 | 
				
			||||||
Starting points for debugging scripting languages etc.
 | 
					 | 
				
			||||||
SysRq
 | 
					SysRq
 | 
				
			||||||
References
 | 
					References
 | 
				
			||||||
Special Thanks
 | 
					Special Thanks
 | 
				
			||||||
| 
						 | 
					@ -44,18 +43,20 @@ Register Set
 | 
				
			||||||
============
 | 
					============
 | 
				
			||||||
The current architectures have the following registers.
 | 
					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 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 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory management,
 | 
					16 Control registers, 32 bit on s/390 and 64 bit on z/Architecture, cr0-cr15,
 | 
				
			||||||
interrupt control,debugging control etc.
 | 
					kernel usage only, used for memory management, interrupt control, debugging
 | 
				
			||||||
 | 
					control etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture
 | 
					16 Access registers (ar0-ar15), 32 bit on both s/390 and z/Architecture,
 | 
				
			||||||
not used by normal programs but potentially could 
 | 
					normally not used by normal programs but potentially could be used as
 | 
				
			||||||
be used as temporary storage. Their main purpose is their 1 to 1
 | 
					temporary storage. These registers have a 1:1 association with general
 | 
				
			||||||
association with general purpose registers and are used in
 | 
					purpose registers and are designed to be used in the so-called access
 | 
				
			||||||
the kernel for copying data between kernel & user address spaces.
 | 
					register mode to select different address spaces.
 | 
				
			||||||
Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit 
 | 
					Access register 0 (and access register 1 on z/Architecture, which needs a
 | 
				
			||||||
pointer ) ) is currently used by the pthread library as a pointer to
 | 
					64 bit pointer) is currently used by the pthread library as a pointer to
 | 
				
			||||||
the current running threads private area.
 | 
					the current running threads private area.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating 
 | 
					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
 | 
					6       6     Input/Output interrupt Mask
 | 
				
			||||||
 | 
					
 | 
				
			||||||
7       7     External interrupt Mask used primarily for interprocessor signalling & 
 | 
					7	7     External interrupt Mask used primarily for interprocessor
 | 
				
			||||||
	      clock interrupts.
 | 
						      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
 | 
					12      12    1 on s/390 0 on z/Architecture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
13      13    Machine Check Mask 1=enable machine check interrupts
 | 
					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 
 | 
					14	14    Wait State. Set this to 1 to stop the processor except for
 | 
				
			||||||
	      time to other LPARS used in CPU idle in the kernel to increase overall 
 | 
						      interrupts and give  time to other LPARS. Used in CPU idle in
 | 
				
			||||||
	      usage of processor resources.
 | 
						      the kernel to increase overall usage of processor resources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
15      15    Problem state ( if set to 1 certain instructions are disabled )
 | 
					15      15    Problem state ( if set to 1 certain instructions are disabled )
 | 
				
			||||||
	      all linux user programs run with this bit 1 
 | 
						      all linux user programs run with this bit 1 
 | 
				
			||||||
| 
						 | 
					@ -170,16 +172,18 @@ s/390 z/Architecture
 | 
				
			||||||
Prefix Page(s)
 | 
					Prefix Page(s)
 | 
				
			||||||
--------------
 | 
					--------------
 | 
				
			||||||
This per cpu memory area is too intimately tied to the processor not to mention.
 | 
					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 
 | 
					It exists between the real addresses 0-4096 on s/390 and between 0-8192 on
 | 
				
			||||||
with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set 
 | 
					z/Architecture and is exchanged with one page on s/390 or two pages on
 | 
				
			||||||
prefix instruction in linux'es startup. 
 | 
					z/Architecture in absolute storage by the set prefix instruction during Linux
 | 
				
			||||||
This page is mapped to a different prefix for each processor in an SMP configuration
 | 
					startup.
 | 
				
			||||||
( assuming the os designer is sane of course :-) ).
 | 
					This page is mapped to a different prefix for each processor in an SMP
 | 
				
			||||||
Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture 
 | 
					configuration (assuming the OS designer is sane of course).
 | 
				
			||||||
are used by the processor itself for holding such information as exception indications & 
 | 
					Bytes 0-512 (200 hex) on s/390 and 0-512, 4096-4544, 4604-5119 currently on
 | 
				
			||||||
entry points for exceptions.
 | 
					z/Architecture are used by the processor itself for holding such information
 | 
				
			||||||
Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture 
 | 
					as exception indications and entry points for exceptions.
 | 
				
			||||||
( there is a gap on z/Architecture too currently between 0xc00 & 1000 which linux uses ).
 | 
					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
 | 
					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
 | 
					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
 | 
					however it means that we now cannot catch stray NULL pointers in the
 | 
				
			||||||
| 
						 | 
					@ -197,8 +201,8 @@ the ascii art.
 | 
				
			||||||
				* Kernel Space	*
 | 
									* Kernel Space	*
 | 
				
			||||||
				*		*
 | 
									*		*
 | 
				
			||||||
				*****************	  ****************
 | 
									*****************	  ****************
 | 
				
			||||||
User Space Himem (typically 0xC0000000 3GB )*  User Stack   *          *              *
 | 
					User Space Himem		*  User Stack	*	  *		 *
 | 
				
			||||||
				            *****************          *              *
 | 
					(typically 0xC0000000 3GB )	*****************	  *		 *
 | 
				
			||||||
				*  Shared Libs	*	  * Next Process *
 | 
									*  Shared Libs	*	  * Next Process *
 | 
				
			||||||
				*****************	  *	to	 *
 | 
									*****************	  *	to	 *
 | 
				
			||||||
				*		*   <==   *	Run	 *  <==
 | 
									*		*   <==   *	Run	 *  <==
 | 
				
			||||||
| 
						 | 
					@ -208,10 +212,10 @@ User Space Himem (typically 0xC0000000 3GB )*  User Stack   *          *
 | 
				
			||||||
				*   Sections	*	  *		 *
 | 
									*   Sections	*	  *		 *
 | 
				
			||||||
0x00000000			*****************	  ****************
 | 
					0x00000000			*****************	  ****************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Now it is easy to see that on Intel it is quite easy to recognise a kernel address 
 | 
					Now it is easy to see that on Intel it is quite easy to recognise a kernel
 | 
				
			||||||
as being one greater than user space himem ( in this case 0xC0000000).
 | 
					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
 | 
					and addresses of less than this are the ones in the current running program on
 | 
				
			||||||
processor ( if an smp box ).
 | 
					this processor (if an smp box).
 | 
				
			||||||
If using the virtual machine ( VM ) as a debugger it is quite difficult to
 | 
					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
 | 
					know which user process is running as the address space you are looking at
 | 
				
			||||||
could be from any process in the run queue.
 | 
					could be from any process in the run queue.
 | 
				
			||||||
| 
						 | 
					@ -301,10 +305,10 @@ Virtual Addresses on s/390 & z/Architecture
 | 
				
			||||||
===========================================
 | 
					===========================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A virtual address on s/390 is made up of 3 parts
 | 
					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 ) 
 | 
					The SX (segment index, roughly corresponding to the PGD & PMD in Linux
 | 
				
			||||||
being bits 1-11.
 | 
					terminology) being bits 1-11.
 | 
				
			||||||
The PX ( page index, corresponding to the page table entry (pte) in linux terminology )
 | 
					The PX (page index, corresponding to the page table entry (pte) in Linux
 | 
				
			||||||
being bits 12-19. 
 | 
					terminology) being bits 12-19.
 | 
				
			||||||
The remaining bits BX (the byte index are the offset in the page )
 | 
					The remaining bits BX (the byte index are the offset in the page )
 | 
				
			||||||
i.e. bits 20 to 31.
 | 
					i.e. bits 20 to 31.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -368,9 +372,9 @@ each processor as follows.
 | 
				
			||||||
            *        ( 8K )        *
 | 
					            *        ( 8K )        *
 | 
				
			||||||
16K aligned ************************ 
 | 
					16K aligned ************************ 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What this means is that we don't need to dedicate any register or global variable
 | 
					What this means is that we don't need to dedicate any register or global
 | 
				
			||||||
to point to the current running process & can retrieve it with the following
 | 
					variable to point to the current running process & can retrieve it with the
 | 
				
			||||||
very simple construct for s/390 & one very similar for z/Architecture.
 | 
					following very simple construct for s/390 & one very similar for z/Architecture.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct task_struct * get_current(void)
 | 
					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.
 | 
					limited knowledge of one assembly language.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
It should be noted that there are some differences between the
 | 
					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
 | 
					s/390 and z/Architecture stack layouts as the z/Architecture stack layout
 | 
				
			||||||
to maintain compatibility with older linkage formats.
 | 
					didn't have to maintain compatibility with older linkage formats.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Glossary:
 | 
					Glossary:
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
| 
						 | 
					@ -588,8 +592,8 @@ A sample program with comments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Comments on the function test
 | 
					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.
 | 
					2) This is a frameless function & no stack is bought.
 | 
				
			||||||
3) The compiler was clever enough to recognise that it could return the
 | 
					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 ( :-) ).
 | 
					value in r2 as well as use it for the passed in parameter ( :-) ).
 | 
				
			||||||
| 
						 | 
					@ -743,35 +747,34 @@ Debugging under VM
 | 
				
			||||||
Notes
 | 
					Notes
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
Addresses & values in the VM debugger are always hex never decimal
 | 
					Addresses & values in the VM debugger are always hex never decimal
 | 
				
			||||||
Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2> 
 | 
					Address ranges are of the format <HexValue1>-<HexValue2> or
 | 
				
			||||||
e.g. The address range  0x2000 to 0x3000 can be described as 2000-3000 or 2000.1000
 | 
					<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.
 | 
					The VM Debugger is case insensitive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VM's strengths are usually other debuggers weaknesses you can get at any resource
 | 
					VM's strengths are usually other debuggers weaknesses you can get at any
 | 
				
			||||||
no matter how sensitive e.g. memory management resources,change address translation
 | 
					resource no matter how sensitive e.g. memory management resources, change
 | 
				
			||||||
in the PSW. For kernel hacking you will reap dividends if you get good at it.
 | 
					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
 | 
					The VM Debugger displays operators but not operands, and also the debugger
 | 
				
			||||||
of it was written when memory was expensive & the programmer was probably proud that
 | 
					displays useful information on the same line as the author of the code probably
 | 
				
			||||||
it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by
 | 
					felt that it was a good idea not to go over the 80 columns on the screen.
 | 
				
			||||||
changing the interface :-), also the debugger displays useful information on the same line & 
 | 
					This isn't as unintuitive as it may seem as the s/390 instructions are easy to
 | 
				
			||||||
the author of the code probably felt that it was a good idea not to go over 
 | 
					decode mentally and you can make a good guess at a lot of them as all the
 | 
				
			||||||
the 80 columns on the screen. 
 | 
					operands are nibble (half byte aligned).
 | 
				
			||||||
 | 
					So if you have an objdump listing by hand, it is quite easy to follow, and if
 | 
				
			||||||
As some of you are probably in a panic now this isn't as unintuitive as it may seem
 | 
					you don't have an objdump listing keep a copy of the s/390 Reference Summary
 | 
				
			||||||
as the 390 instructions are easy to decode mentally & you can make a good guess at a lot 
 | 
					or alternatively the s/390 principles of operation next to you.
 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
e.g. even I can guess that 
 | 
					e.g. even I can guess that 
 | 
				
			||||||
0001AFF8' LR    180F        CC 0
 | 
					0001AFF8' LR    180F        CC 0
 | 
				
			||||||
is a ( load register ) lr r0,r15 
 | 
					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
 | 
					Also it is very easy to tell the length of a 390 instruction from the 2 most
 | 
				
			||||||
bits in the instruction ( not that this info is really useful except if you are trying to
 | 
					significant bits in the instruction (not that this info is really useful except
 | 
				
			||||||
make sense of a hexdump of code ).
 | 
					if you are trying to make sense of a hexdump of code).
 | 
				
			||||||
Here is a table
 | 
					Here is a table
 | 
				
			||||||
Bits                    Instruction Length
 | 
					Bits                    Instruction Length
 | 
				
			||||||
------------------------------------------
 | 
					------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -780,9 +783,6 @@ Bits                    Instruction Length
 | 
				
			||||||
10                          4 Bytes
 | 
					10                          4 Bytes
 | 
				
			||||||
11                          6 Bytes
 | 
					11                          6 Bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The debugger also displays other useful info on the same line such as the
 | 
					The debugger also displays other useful info on the same line such as the
 | 
				
			||||||
addresses being operated on destination addresses of branches & condition codes.
 | 
					addresses being operated on destination addresses of branches & condition codes.
 | 
				
			||||||
e.g.  
 | 
					e.g.  
 | 
				
			||||||
| 
						 | 
					@ -853,8 +853,8 @@ Displaying & modifying Registers
 | 
				
			||||||
--------------------------------
 | 
					--------------------------------
 | 
				
			||||||
D G will display all the gprs
 | 
					D G will display all the gprs
 | 
				
			||||||
Adding a extra G to all the commands is necessary to access the full 64 bit 
 | 
					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
 | 
					content in VM on z/Architecture. Obviously this isn't required for access
 | 
				
			||||||
as these are still 32 bit.
 | 
					registers as these are still 32 bit.
 | 
				
			||||||
e.g. DGG instead of DG 
 | 
					e.g. DGG instead of DG 
 | 
				
			||||||
D X will display all the control registers
 | 
					D X will display all the control registers
 | 
				
			||||||
D AR will display all the access registers
 | 
					D AR will display all the access registers
 | 
				
			||||||
| 
						 | 
					@ -870,7 +870,8 @@ Displaying Memory
 | 
				
			||||||
-----------------
 | 
					-----------------
 | 
				
			||||||
To display memory mapped using the current PSW's mapping try
 | 
					To display memory mapped using the current PSW's mapping try
 | 
				
			||||||
D <range>
 | 
					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.
 | 
					D I<range> will disassemble/display a range of instructions.
 | 
				
			||||||
ST addr 32 bit word will store a 32 bit aligned address
 | 
					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)
 | 
				
			||||||
| 
						 | 
					@ -884,8 +885,8 @@ restore it.
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
Hints
 | 
					Hints
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
If you want to issue a debugger command without halting your virtual machine with the
 | 
					If you want to issue a debugger command without halting your virtual machine
 | 
				
			||||||
PA1 key try prefixing the command with #CP e.g.
 | 
					with the PA1 key try prefixing the command with #CP e.g.
 | 
				
			||||||
#cp tr i pswa 2000
 | 
					#cp tr i pswa 2000
 | 
				
			||||||
also suffixing most debugger commands with RUN will cause them not
 | 
					also suffixing most debugger commands with RUN will cause them not
 | 
				
			||||||
to stop just display the mnemonic at the current instruction on the console.
 | 
					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
 | 
					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
 | 
					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 
 | 
					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.
 | 
					entering the msgs by hand), however, the trick might be useful for a single
 | 
				
			||||||
On linux'es 3270 emulator x3270 there is a very useful option under the file ment
 | 
					object file. In the 3270 terminal emulator x3270 there is a very useful option
 | 
				
			||||||
Save Screens In File this is very good of keeping a copy of traces. 
 | 
					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. 
 | 
					From CMS help <command name> will give you online help on a particular command. 
 | 
				
			||||||
e.g. 
 | 
					e.g. 
 | 
				
			||||||
| 
						 | 
					@ -920,7 +922,8 @@ SET PF9 IMM B
 | 
				
			||||||
This does a single step in VM on pressing F8. 
 | 
					This does a single step in VM on pressing F8. 
 | 
				
			||||||
SET PF10  ^
 | 
					SET PF10  ^
 | 
				
			||||||
This sets up the ^ key.
 | 
					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 ^-
 | 
					SET PF11 ^-
 | 
				
			||||||
This types the starting keystrokes for a sysrq see SysRq below.
 | 
					This types the starting keystrokes for a sysrq see SysRq below.
 | 
				
			||||||
SET PF12 RETRIEVE
 | 
					SET PF12 RETRIEVE
 | 
				
			||||||
| 
						 | 
					@ -1014,8 +1017,8 @@ Tracing Program Exceptions
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
If you get a crash which says something like
 | 
					If you get a crash which says something like
 | 
				
			||||||
illegal operation or specification exception followed by a register dump
 | 
					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
 | 
					The most common ones you will normally be tracing for is
 | 
				
			||||||
| 
						 | 
					@ -1057,9 +1060,10 @@ TR GOTO INITIAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tracing linux syscalls under VM
 | 
					Tracing linux syscalls under VM
 | 
				
			||||||
-------------------------------
 | 
					-------------------------------
 | 
				
			||||||
Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 
 | 
					Syscalls are implemented on Linux for S390 by the Supervisor call instruction
 | 
				
			||||||
possibilities of these as the instruction is made up of a  0xA opcode & the second byte being
 | 
					(SVC). There 256 possibilities of these as the instruction is made up of a 0xA
 | 
				
			||||||
the syscall number. They are traced using the simple command.
 | 
					opcode and the second byte being the syscall number. They are traced using the
 | 
				
			||||||
 | 
					simple command:
 | 
				
			||||||
TR SVC  <Optional value or range>
 | 
					TR SVC  <Optional value or range>
 | 
				
			||||||
the syscalls are defined in linux/arch/s390/include/asm/unistd.h
 | 
					the syscalls are defined in linux/arch/s390/include/asm/unistd.h
 | 
				
			||||||
e.g. to trace all file opens just do
 | 
					e.g. to trace all file opens just do
 | 
				
			||||||
| 
						 | 
					@ -1070,12 +1074,12 @@ SMP Specific commands
 | 
				
			||||||
---------------------
 | 
					---------------------
 | 
				
			||||||
To find out how many cpus you have
 | 
					To find out how many cpus you have
 | 
				
			||||||
Q CPUS displays all the CPU's available to your virtual machine
 | 
					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
 | 
					To find the cpu that the current cpu VM debugger commands are being directed at
 | 
				
			||||||
Q CPU to change the current cpu VM debugger commands are being directed at do
 | 
					do Q CPU to change the current cpu VM debugger commands are being directed at do
 | 
				
			||||||
CPU <desired cpu no>
 | 
					CPU <desired cpu no>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On a SMP guest issue a command to all CPUs try prefixing the command with cpu all.
 | 
					On a SMP guest issue a command to all CPUs try prefixing the command with cpu
 | 
				
			||||||
To issue a command to a particular cpu try cpu <cpu number> e.g.
 | 
					all. To issue a command to a particular cpu try cpu <cpu number> e.g.
 | 
				
			||||||
CPU 01 TR I R 2000.3000
 | 
					CPU 01 TR I R 2000.3000
 | 
				
			||||||
If you are running on a guest with several cpus & you have a IO related problem
 | 
					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.
 | 
					& cannot follow the flow of code but you know it isn't smp related.
 | 
				
			||||||
| 
						 | 
					@ -1101,10 +1105,10 @@ D TX0.100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Alternatively
 | 
					Alternatively
 | 
				
			||||||
=============
 | 
					=============
 | 
				
			||||||
Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which
 | 
					Under older VM debuggers (I love EBDIC too) you can use following little
 | 
				
			||||||
will convert a command line of hex digits to ascii text which can be compiled under linux & 
 | 
					program which converts a command line of hex digits to ascii text. It can be
 | 
				
			||||||
you can copy the hex digits from your x3270 terminal to your xterm if you are debugging
 | 
					compiled under linux and you can copy the hex digits from your x3270 terminal
 | 
				
			||||||
from a linuxbox.
 | 
					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
 | 
					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 ).
 | 
					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
 | 
					We have stopped at a breakpoint
 | 
				
			||||||
000151B0' SVC   0A05     -> 0001909A'   CC 0
 | 
					000151B0' SVC   0A05     -> 0001909A'   CC 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
D 20.8 to check the SVC old psw in the prefix area & see was it from userspace
 | 
					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 P18 of the s/390 390 Reference Summary 
 | 
					(for the layout of the prefix area consult the "Fixed Storage Locations"
 | 
				
			||||||
if you have it available ).
 | 
					chapter of the s/390 Reference Summary if you have it available).
 | 
				
			||||||
V00000020  070C2000 800151B2
 | 
					V00000020  070C2000 800151B2
 | 
				
			||||||
The problem state bit wasn't set &  it's also too early in the boot sequence
 | 
					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 
 | 
					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
 | 
					psw to user space addressing so we could get at the first parameter of the open
 | 
				
			||||||
gpr2.
 | 
					in gpr2.
 | 
				
			||||||
Next do a 
 | 
					Next do a 
 | 
				
			||||||
D G2
 | 
					D G2
 | 
				
			||||||
GPR  2 =  00014CB4
 | 
					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
 | 
					When your backchain reaches a dead end
 | 
				
			||||||
--------------------------------------
 | 
					--------------------------------------
 | 
				
			||||||
This can happen when an exception happens in the kernel & the kernel is entered twice
 | 
					This can happen when an exception happens in the kernel and the kernel is
 | 
				
			||||||
if you reach the NULL pointer at the end of the back chain you should be
 | 
					entered twice. If you reach the NULL pointer at the end of the back chain you
 | 
				
			||||||
able to sniff further back if you follow the following tricks.
 | 
					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
 | 
					1) A kernel address should be easy to recognise since it is in
 | 
				
			||||||
primary space & the problem state bit isn't set & also
 | 
					primary space & the problem state bit isn't set & also
 | 
				
			||||||
The Hi bit of the address is set.
 | 
					The Hi bit of the address is set.
 | 
				
			||||||
| 
						 | 
					@ -1260,8 +1264,8 @@ V000FFFD0  00010400 80010802 8001085A 000FFFA0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
our 3rd return address is 8001085A
 | 
					our 3rd return address is 8001085A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines
 | 
					as the 04B52002 looks suspiciously like rubbish it is fair to assume that the
 | 
				
			||||||
for the sake of optimisation don't set up a backchain.
 | 
					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.
 | 
					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
 | 
					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
 | 
					I am not going to give a course in 390 IO architecture as this would take me
 | 
				
			||||||
while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have 
 | 
					quite a while and I'm no expert. Instead I'll give a 390 IO architecture
 | 
				
			||||||
the s/390 principles of operation available read this instead. If nothing else you may find a few 
 | 
					summary for Dummies. If you have the s/390 principles of operation available
 | 
				
			||||||
useful keywords in here & be able to use them on a web search engine like altavista to find 
 | 
					read this instead. If nothing else you may find a few useful keywords in here
 | 
				
			||||||
more useful information.
 | 
					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
 | 
					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,
 | 
					fibre optics and devices such as tapes and disks can be shared between several
 | 
				
			||||||
also S390 can support up to 65536 devices while a high end PC based system might be choking
 | 
					mainframes. Also S390 can support up to 65536 devices while a high end PC based
 | 
				
			||||||
with around 64. Here is some of the common IO terminology
 | 
					system might be choking with around 64.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is some of the common IO terminology:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Subchannel:
 | 
					Subchannel:
 | 
				
			||||||
This is the logical number most IO commands use to talk to an IO device there can be up to
 | 
					This is the logical number most IO commands use to talk to an IO device. There
 | 
				
			||||||
0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM
 | 
					can be up to 0x10000 (65536) of these in a configuration, typically there are a
 | 
				
			||||||
for simplicity they are allocated contiguously, however on the native hardware they are not
 | 
					few hundred. Under VM for simplicity they are allocated contiguously, however
 | 
				
			||||||
they typically stay consistent between boots provided no new hardware is inserted or removed.
 | 
					on the native hardware they are not. They typically stay consistent between
 | 
				
			||||||
Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL,
 | 
					boots provided no new hardware is inserted or removed.
 | 
				
			||||||
HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & 
 | 
					Under Linux for s390 we use these as IRQ's and also when issuing an IO command
 | 
				
			||||||
TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most
 | 
					(CLEAR SUBCHANNEL, HALT SUBCHANNEL, MODIFY SUBCHANNEL, RESUME SUBCHANNEL,
 | 
				
			||||||
important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check
 | 
					START SUBCHANNEL, STORE SUBCHANNEL and TEST SUBCHANNEL). We use this as the ID
 | 
				
			||||||
whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel
 | 
					of the device we wish to talk to. The most important of these instructions are
 | 
				
			||||||
can have up to 8 channel paths to a device this offers redundancy if one is not available.
 | 
					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:
 | 
					Device Number:
 | 
				
			||||||
This number remains static & Is closely tied to the hardware, there are 65536 of these
 | 
					This number remains static and is closely tied to the hardware. There are 65536
 | 
				
			||||||
also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) 
 | 
					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
 | 
					another lsb 8 bits. These remain static even if more devices are inserted or
 | 
				
			||||||
from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided
 | 
					removed from the hardware. There is a 1 to 1 mapping between subchannels and
 | 
				
			||||||
devices aren't inserted or removed.
 | 
					device numbers, provided devices aren't inserted or removed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Channel Control Words:
 | 
					Channel Control Words:
 | 
				
			||||||
CCWS are linked lists of instructions initially pointed to by an operation request block (ORB),
 | 
					CCWs are linked lists of instructions initially pointed to by an operation
 | 
				
			||||||
which is initially given to Start Subchannel (SSCH) command along with the subchannel number
 | 
					request block (ORB), which is initially given to Start Subchannel (SSCH)
 | 
				
			||||||
for the IO subsystem to process while the CPU continues executing normal code.
 | 
					command along with the subchannel number for the IO subsystem to process
 | 
				
			||||||
These come in two flavours, Format 0 ( 24 bit for backward )
 | 
					while the CPU continues executing normal code.
 | 
				
			||||||
compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write 
 | 
					CCWs come in two flavours, Format 0 (24 bit for backward compatibility) and
 | 
				
			||||||
( & many other instructions ) they consist of a length field & an absolute address field.
 | 
					Format 1 (31 bit). These are typically used to issue read and write (and many
 | 
				
			||||||
For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the
 | 
					other) instructions. They consist of a length field and an absolute address
 | 
				
			||||||
channel is idle & the second for device end ( secondary status ) sometimes you get both
 | 
					field.
 | 
				
			||||||
concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each interrupt,
 | 
					Each IO typically gets 1 or 2 interrupts, one for channel end (primary status)
 | 
				
			||||||
from which you receive an Interruption response block (IRB). If you get channel & device end 
 | 
					when the channel is idle, and the second for device end (secondary status).
 | 
				
			||||||
status in the IRB without channel checks etc. your IO probably went okay. If you didn't you
 | 
					Sometimes you get both concurrently. You check how the IO went on by issuing a
 | 
				
			||||||
probably need a doctor to examine the IRB & extended status word etc.
 | 
					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
 | 
					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
 | 
					concurrent sense. This means that if an error occurs Extended sense information
 | 
				
			||||||
be presented in the Extended status word in the IRB if not you have to issue a
 | 
					will be presented in the Extended status word in the IRB. If not you have to
 | 
				
			||||||
subsequent SENSE CCW command after the test subchannel. 
 | 
					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
 | 
					TPI (Test pending interrupt) can also be used for polled IO, but in
 | 
				
			||||||
systems it isn't recommended except for checking special cases ( i.e. non looping checks for
 | 
					multitasking multiprocessor systems it isn't recommended except for
 | 
				
			||||||
pending IO etc. ).
 | 
					checking special cases (i.e. non looping checks for pending IO etc.).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics
 | 
					Store Subchannel and Modify Subchannel can be used to examine and modify
 | 
				
			||||||
of a subchannel ( e.g. channel paths ).
 | 
					operating characteristics of a subchannel (e.g. channel paths).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Other IO related Terms:
 | 
					Other IO related Terms:
 | 
				
			||||||
Sysplex: S390's Clustering Technology
 | 
					Sysplex: S390's Clustering Technology
 | 
				
			||||||
QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet,
 | 
					QDIO: S390's new high speed IO architecture to support devices such as gigabit
 | 
				
			||||||
this architecture is also designed to be forward compatible with up & coming 64 bit machines.
 | 
					ethernet, this architecture is also designed to be forward compatible with
 | 
				
			||||||
 | 
					upcoming 64 bit machines.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
General Concepts 
 | 
					General Concepts 
 | 
				
			||||||
| 
						 | 
					@ -1406,28 +1418,31 @@ sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers
 | 
				
			||||||
Interface (OEMI).
 | 
					Interface (OEMI).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This byte wide Parallel channel path/bus has parity & data on the "Bus" cable 
 | 
					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
 | 
					and control lines on the "Tag" cable. These can operate in byte multiplex mode
 | 
				
			||||||
sharing between several slow devices or burst mode & monopolize the channel for the
 | 
					for sharing between several slow devices or burst mode and monopolize the
 | 
				
			||||||
whole burst. Up to 256 devices can be addressed  on one of these cables. These cables are
 | 
					channel for the whole burst. Up to 256 devices can be addressed on one of these
 | 
				
			||||||
about one inch in diameter. The maximum unextended length supported by these cables is
 | 
					cables. These cables are about one inch in diameter. The maximum unextended
 | 
				
			||||||
125 Meters but this can be extended up to 2km with a fibre optic channel extended 
 | 
					length supported by these cables is 125 Meters but this can be extended up to
 | 
				
			||||||
such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however
 | 
					2km with a fibre optic channel extended such as a 3044. The maximum burst speed
 | 
				
			||||||
some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec.
 | 
					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.
 | 
					One of these paths can be daisy chained to up to 8 control units.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ESCON if fibre optic it is also called FICON 
 | 
					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
 | 
					Was introduced by IBM in 1990. Has 2 fibre optic cables and uses either leds or
 | 
				
			||||||
for communication at a signaling rate of up to 200 megabits/sec. As 10bits are transferred
 | 
					lasers for communication at a signaling rate of up to 200 megabits/sec. As
 | 
				
			||||||
for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once
 | 
					10bits are transferred for every 8 bits info this drops to 160 megabits/sec
 | 
				
			||||||
control info & CRC are added. ESCON only operates in burst mode.
 | 
					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
 | 
					ESCONs typical max cable length is 3km for the led version and 20km for the
 | 
				
			||||||
known as XDF ( extended distance facility ). This can be further extended by using an
 | 
					laser version known as XDF (extended distance facility). This can be further
 | 
				
			||||||
ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is
 | 
					extended by using an ESCON director which triples the above mentioned ranges.
 | 
				
			||||||
serial it uses a packet switching architecture the standard Bus & Tag control protocol
 | 
					Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture,
 | 
				
			||||||
is however present within the packets. Up to 256 devices can be attached to each control
 | 
					the standard Bus & Tag control protocol is however present within the packets.
 | 
				
			||||||
unit that uses one of these interfaces.
 | 
					Up to 256 devices can be attached to each control unit that uses one of these
 | 
				
			||||||
 | 
					interfaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Common 390 Devices include:
 | 
					Common 390 Devices include:
 | 
				
			||||||
Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters,
 | 
					Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters,
 | 
				
			||||||
| 
						 | 
					@ -1436,7 +1451,7 @@ DASD's direct access storage devices ( otherwise known as hard disks ).
 | 
				
			||||||
Tape Drives.
 | 
					Tape Drives.
 | 
				
			||||||
CTC ( Channel to Channel Adapters ),
 | 
					CTC ( Channel to Channel Adapters ),
 | 
				
			||||||
ESCON or Parallel Cables used as a very high speed serial link
 | 
					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
 | 
					Debugging IO on s/390 & z/Architecture under VM
 | 
				
			||||||
| 
						 | 
					@ -1475,9 +1490,9 @@ or the halt subchannels
 | 
				
			||||||
or TR HSCH 7C08-7C09
 | 
					or TR HSCH 7C08-7C09
 | 
				
			||||||
MSCH's ,STSCH's I think you can guess the rest
 | 
					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
 | 
					A good trick is tracing all the IO's and CCWS and spooling them into the reader
 | 
				
			||||||
VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you
 | 
					of another VM guest so he can ftp the logfile back to his own machine. I'll do
 | 
				
			||||||
 a look at the output.
 | 
					a small bit of this and give you a look at the output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1) Spool stdout to VM reader
 | 
					1) Spool stdout to VM reader
 | 
				
			||||||
SP PRT TO (another vm guest ) or * for the local vm guest
 | 
					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 breakpoints: shows all current breakpoints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
info stack: shows stack back trace ( if this doesn't work too well, I'll show you the
 | 
					info stack: shows stack back trace (if this doesn't work too well, I'll show
 | 
				
			||||||
stacktrace by hand below ).
 | 
					you the stacktrace by hand below).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
info locals: displays local variables.
 | 
					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.
 | 
					stepi: steps a single machine code instruction.
 | 
				
			||||||
e.g. stepi 100
 | 
					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
 | 
					finish: will run until exit of the current routine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1721,7 +1737,8 @@ e.g.
 | 
				
			||||||
outputs:
 | 
					outputs:
 | 
				
			||||||
$1 = 11 
 | 
					$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)
 | 
					(gdb) call fflush(stdout)
 | 
				
			||||||
hello world$2 = 0
 | 
					hello world$2 = 0
 | 
				
			||||||
As an aside the debugger also calls malloc & free under the hood 
 | 
					As an aside the debugger also calls malloc & free under the hood 
 | 
				
			||||||
| 
						 | 
					@ -1804,26 +1821,17 @@ man gdb or info gdb.
 | 
				
			||||||
core dumps
 | 
					core dumps
 | 
				
			||||||
----------
 | 
					----------
 | 
				
			||||||
What a core dump ?,
 | 
					What a core dump ?,
 | 
				
			||||||
A core dump is a file generated by the kernel ( if allowed ) which contains the registers,
 | 
					A core dump is a file generated by the kernel (if allowed) which contains the
 | 
				
			||||||
& all active pages of the program which has crashed.
 | 
					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 & memory of the
 | 
					From this file gdb will allow you to look at the registers, stack trace and
 | 
				
			||||||
program as if it just crashed on your system, it is usually called core & created in the
 | 
					memory of the program as if it just crashed on your system. It is usually
 | 
				
			||||||
current working directory.
 | 
					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
 | 
					This is very useful in that a customer can mail a core dump to a technical
 | 
				
			||||||
& the technical support department can reconstruct what happened.
 | 
					support department and the technical support department can reconstruct what
 | 
				
			||||||
Provided they have an identical copy of this program with debugging symbols compiled in &
 | 
					happened. Provided they have an identical copy of this program with debugging
 | 
				
			||||||
the source base of this build is available.
 | 
					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.
 | 
					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.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Why have I never seen one ?.
 | 
					Why have I never seen one ?.
 | 
				
			||||||
Probably because you haven't used the command 
 | 
					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
 | 
					#3  0x5167e6 in readline_internal_char () at readline.c:454
 | 
				
			||||||
#4  0x5168ee in readline_internal_charloop () at readline.c:507
 | 
					#4  0x5168ee in readline_internal_charloop () at readline.c:507
 | 
				
			||||||
#5  0x51692c in readline_internal () at readline.c:521
 | 
					#5  0x51692c in readline_internal () at readline.c:521
 | 
				
			||||||
#6  0x5164fe in readline (prompt=0x7ffff810 "\177ÿøx\177ÿ÷Ø\177ÿøxÀ")
 | 
					#6  0x5164fe in readline (prompt=0x7ffff810)
 | 
				
			||||||
    at readline.c:349
 | 
					    at readline.c:349
 | 
				
			||||||
#7  0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1,
 | 
					#7  0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1,
 | 
				
			||||||
    annotation_suffix=0x4d6b44 "prompt") at top.c:2091
 | 
					    annotation_suffix=0x4d6b44 "prompt") at top.c:2091
 | 
				
			||||||
| 
						 | 
					@ -1929,8 +1937,8 @@ cat /proc/sys/net/ipv4/ip_forward
 | 
				
			||||||
On my machine now outputs
 | 
					On my machine now outputs
 | 
				
			||||||
1
 | 
					1
 | 
				
			||||||
IP forwarding is on.
 | 
					IP forwarding is on.
 | 
				
			||||||
There is a lot of useful info in here best found by going in & having a look around,
 | 
					There is a lot of useful info in here best found by going in and having a look
 | 
				
			||||||
so I'll take you through some entries I consider important.
 | 
					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
 | 
					All the processes running on the machine have their own entry defined by
 | 
				
			||||||
/proc/<pid>
 | 
					/proc/<pid>
 | 
				
			||||||
| 
						 | 
					@ -2060,7 +2068,8 @@ if the device doesn't say up
 | 
				
			||||||
try
 | 
					try
 | 
				
			||||||
/etc/rc.d/init.d/network start 
 | 
					/etc/rc.d/init.d/network start 
 | 
				
			||||||
( this starts the network stack & hopefully calls ifconfig tr0 up ).
 | 
					( 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.
 | 
					Now ping the device from a machine in the same subnet.
 | 
				
			||||||
if the RX packets count & TX packets counts don't increment you probably
 | 
					if the RX packets count & TX packets counts don't increment you probably
 | 
				
			||||||
have problems.
 | 
					have problems.
 | 
				
			||||||
| 
						 | 
					@ -2086,34 +2095,6 @@ of the device.
 | 
				
			||||||
See the manpage chandev.8 &type cat /proc/chandev for more info.
 | 
					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
 | 
					SysRq
 | 
				
			||||||
=====
 | 
					=====
 | 
				
			||||||
This is now supported by linux for s/390 & z/Architecture.
 | 
					This is now supported by linux for s/390 & z/Architecture.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| 
						 | 
					@ -726,10 +726,14 @@ KBUILD_CFLAGS 	+= $(call cc-option, -femit-struct-debug-baseonly) \
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
 | 
					ifndef CC_FLAGS_FTRACE
 | 
				
			||||||
 | 
					CC_FLAGS_FTRACE := -pg
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					export CC_FLAGS_FTRACE
 | 
				
			||||||
ifdef CONFIG_HAVE_FENTRY
 | 
					ifdef CONFIG_HAVE_FENTRY
 | 
				
			||||||
CC_USING_FENTRY	:= $(call cc-option, -mfentry -DCC_USING_FENTRY)
 | 
					CC_USING_FENTRY	:= $(call cc-option, -mfentry -DCC_USING_FENTRY)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
KBUILD_CFLAGS	+= -pg $(CC_USING_FENTRY)
 | 
					KBUILD_CFLAGS	+= $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY)
 | 
				
			||||||
KBUILD_AFLAGS	+= $(CC_USING_FENTRY)
 | 
					KBUILD_AFLAGS	+= $(CC_USING_FENTRY)
 | 
				
			||||||
ifdef CONFIG_DYNAMIC_FTRACE
 | 
					ifdef CONFIG_DYNAMIC_FTRACE
 | 
				
			||||||
	ifdef CONFIG_HAVE_C_RECORDMCOUNT
 | 
						ifdef CONFIG_HAVE_C_RECORDMCOUNT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,7 @@ config S390
 | 
				
			||||||
	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 | 
						select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 | 
				
			||||||
	select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
 | 
						select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
 | 
				
			||||||
	select ARCH_HAS_GCOV_PROFILE_ALL
 | 
						select ARCH_HAS_GCOV_PROFILE_ALL
 | 
				
			||||||
 | 
						select ARCH_HAS_SG_CHAIN
 | 
				
			||||||
	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 | 
						select ARCH_HAVE_NMI_SAFE_CMPXCHG
 | 
				
			||||||
	select ARCH_INLINE_READ_LOCK
 | 
						select ARCH_INLINE_READ_LOCK
 | 
				
			||||||
	select ARCH_INLINE_READ_LOCK_BH
 | 
						select ARCH_INLINE_READ_LOCK_BH
 | 
				
			||||||
| 
						 | 
					@ -116,7 +117,6 @@ config S390
 | 
				
			||||||
	select HAVE_BPF_JIT if 64BIT && PACK_STACK
 | 
						select HAVE_BPF_JIT if 64BIT && PACK_STACK
 | 
				
			||||||
	select HAVE_CMPXCHG_DOUBLE
 | 
						select HAVE_CMPXCHG_DOUBLE
 | 
				
			||||||
	select HAVE_CMPXCHG_LOCAL
 | 
						select HAVE_CMPXCHG_LOCAL
 | 
				
			||||||
	select HAVE_C_RECORDMCOUNT
 | 
					 | 
				
			||||||
	select HAVE_DEBUG_KMEMLEAK
 | 
						select HAVE_DEBUG_KMEMLEAK
 | 
				
			||||||
	select HAVE_DYNAMIC_FTRACE if 64BIT
 | 
						select HAVE_DYNAMIC_FTRACE if 64BIT
 | 
				
			||||||
	select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
 | 
						select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
 | 
				
			||||||
| 
						 | 
					@ -151,7 +151,6 @@ config S390
 | 
				
			||||||
	select TTY
 | 
						select TTY
 | 
				
			||||||
	select VIRT_CPU_ACCOUNTING
 | 
						select VIRT_CPU_ACCOUNTING
 | 
				
			||||||
	select VIRT_TO_BUS
 | 
						select VIRT_TO_BUS
 | 
				
			||||||
	select ARCH_HAS_SG_CHAIN
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SCHED_OMIT_FRAME_POINTER
 | 
					config SCHED_OMIT_FRAME_POINTER
 | 
				
			||||||
	def_bool y
 | 
						def_bool y
 | 
				
			||||||
| 
						 | 
					@ -185,6 +184,10 @@ config HAVE_MARCH_ZEC12_FEATURES
 | 
				
			||||||
	def_bool n
 | 
						def_bool n
 | 
				
			||||||
	select HAVE_MARCH_Z196_FEATURES
 | 
						select HAVE_MARCH_Z196_FEATURES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config HAVE_MARCH_Z13_FEATURES
 | 
				
			||||||
 | 
						def_bool n
 | 
				
			||||||
 | 
						select HAVE_MARCH_ZEC12_FEATURES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
choice
 | 
					choice
 | 
				
			||||||
	prompt "Processor type"
 | 
						prompt "Processor type"
 | 
				
			||||||
	default MARCH_G5
 | 
						default MARCH_G5
 | 
				
			||||||
| 
						 | 
					@ -244,6 +247,14 @@ config MARCH_ZEC12
 | 
				
			||||||
	  2827 series). The kernel will be slightly faster but will not work on
 | 
						  2827 series). The kernel will be slightly faster but will not work on
 | 
				
			||||||
	  older machines.
 | 
						  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
 | 
					endchoice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config MARCH_G5_TUNE
 | 
					config MARCH_G5_TUNE
 | 
				
			||||||
| 
						 | 
					@ -267,6 +278,9 @@ config MARCH_Z196_TUNE
 | 
				
			||||||
config MARCH_ZEC12_TUNE
 | 
					config MARCH_ZEC12_TUNE
 | 
				
			||||||
	def_bool TUNE_ZEC12 || MARCH_ZEC12 && TUNE_DEFAULT
 | 
						def_bool TUNE_ZEC12 || MARCH_ZEC12 && TUNE_DEFAULT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config MARCH_Z13_TUNE
 | 
				
			||||||
 | 
						def_bool TUNE_Z13 || MARCH_Z13 && TUNE_DEFAULT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
choice
 | 
					choice
 | 
				
			||||||
	prompt "Tune code generation"
 | 
						prompt "Tune code generation"
 | 
				
			||||||
	default TUNE_DEFAULT
 | 
						default TUNE_DEFAULT
 | 
				
			||||||
| 
						 | 
					@ -305,6 +319,9 @@ config TUNE_Z196
 | 
				
			||||||
config TUNE_ZEC12
 | 
					config TUNE_ZEC12
 | 
				
			||||||
	bool "IBM zBC12 and zEC12"
 | 
						bool "IBM zBC12 and zEC12"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config TUNE_Z13
 | 
				
			||||||
 | 
						bool "IBM z13"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endchoice
 | 
					endchoice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config 64BIT
 | 
					config 64BIT
 | 
				
			||||||
| 
						 | 
					@ -356,14 +373,14 @@ config SMP
 | 
				
			||||||
	  Even if you don't know what to do here, say Y.
 | 
						  Even if you don't know what to do here, say Y.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config NR_CPUS
 | 
					config NR_CPUS
 | 
				
			||||||
	int "Maximum number of CPUs (2-256)"
 | 
						int "Maximum number of CPUs (2-512)"
 | 
				
			||||||
	range 2 256
 | 
						range 2 512
 | 
				
			||||||
	depends on SMP
 | 
						depends on SMP
 | 
				
			||||||
	default "32" if !64BIT
 | 
						default "32" if !64BIT
 | 
				
			||||||
	default "64" if 64BIT
 | 
						default "64" if 64BIT
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This allows you to specify the maximum number of CPUs which this
 | 
						  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.
 | 
						  minimum value which makes sense is 2.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  This is purely to save memory - each supported CPU adds
 | 
						  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#.
 | 
						  can be controlled through /sys/devices/system/cpu/cpu#.
 | 
				
			||||||
	  Say N if you want to disable CPU hotplug.
 | 
						  Say N if you want to disable CPU hotplug.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SCHED_SMT
 | 
				
			||||||
 | 
						def_bool n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SCHED_MC
 | 
					config SCHED_MC
 | 
				
			||||||
	def_bool n
 | 
						def_bool n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SCHED_BOOK
 | 
					config SCHED_BOOK
 | 
				
			||||||
 | 
						def_bool n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SCHED_TOPOLOGY
 | 
				
			||||||
	def_bool y
 | 
						def_bool y
 | 
				
			||||||
	prompt "Book scheduler support"
 | 
						prompt "Topology scheduler support"
 | 
				
			||||||
	depends on SMP
 | 
						depends on SMP
 | 
				
			||||||
 | 
						select SCHED_SMT
 | 
				
			||||||
	select SCHED_MC
 | 
						select SCHED_MC
 | 
				
			||||||
 | 
						select SCHED_BOOK
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Book scheduler support improves the CPU scheduler's decision making
 | 
						  Topology scheduler support improves the CPU scheduler's decision
 | 
				
			||||||
	  when dealing with machines that have several books.
 | 
						  making when dealing with machines that have multi-threading,
 | 
				
			||||||
 | 
						  multiple cores or multiple books.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source kernel/Kconfig.preempt
 | 
					source kernel/Kconfig.preempt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@ mflags-$(CONFIG_MARCH_Z9_109) := -march=z9-109
 | 
				
			||||||
mflags-$(CONFIG_MARCH_Z10)    := -march=z10
 | 
					mflags-$(CONFIG_MARCH_Z10)    := -march=z10
 | 
				
			||||||
mflags-$(CONFIG_MARCH_Z196)   := -march=z196
 | 
					mflags-$(CONFIG_MARCH_Z196)   := -march=z196
 | 
				
			||||||
mflags-$(CONFIG_MARCH_ZEC12)  := -march=zEC12
 | 
					mflags-$(CONFIG_MARCH_ZEC12)  := -march=zEC12
 | 
				
			||||||
 | 
					mflags-$(CONFIG_MARCH_Z13)   := -march=z13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
aflags-y += $(mflags-y)
 | 
					aflags-y += $(mflags-y)
 | 
				
			||||||
cflags-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_Z10_TUNE)		+= -mtune=z10
 | 
				
			||||||
cflags-$(CONFIG_MARCH_Z196_TUNE)	+= -mtune=z196
 | 
					cflags-$(CONFIG_MARCH_Z196_TUNE)	+= -mtune=z196
 | 
				
			||||||
cflags-$(CONFIG_MARCH_ZEC12_TUNE)	+= -mtune=zEC12
 | 
					cflags-$(CONFIG_MARCH_ZEC12_TUNE)	+= -mtune=zEC12
 | 
				
			||||||
 | 
					cflags-$(CONFIG_MARCH_Z13_TUNE)	+= -mtune=z13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#KBUILD_IMAGE is necessary for make rpm
 | 
					#KBUILD_IMAGE is necessary for make rpm
 | 
				
			||||||
KBUILD_IMAGE	:=arch/s390/boot/image
 | 
					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
 | 
					cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 | 
				
			||||||
endif
 | 
					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	+= -mbackchain -msoft-float $(cflags-y)
 | 
				
			||||||
KBUILD_CFLAGS	+= -pipe -fno-strength-reduce -Wno-sign-compare
 | 
					KBUILD_CFLAGS	+= -pipe -fno-strength-reduce -Wno-sign-compare
 | 
				
			||||||
KBUILD_AFLAGS	+= $(aflags-y)
 | 
					KBUILD_AFLAGS	+= $(aflags-y)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
#include <asm/page.h>
 | 
					#include <asm/page.h>
 | 
				
			||||||
 | 
					#include <asm/sclp.h>
 | 
				
			||||||
#include <asm/ipl.h>
 | 
					#include <asm/ipl.h>
 | 
				
			||||||
#include "sizes.h"
 | 
					#include "sizes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,8 +64,6 @@ static unsigned long free_mem_end_ptr;
 | 
				
			||||||
#include "../../../../lib/decompress_unxz.c"
 | 
					#include "../../../../lib/decompress_unxz.c"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern _sclp_print_early(const char *);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int puts(const char *s)
 | 
					static int puts(const char *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_sclp_print_early(s);
 | 
						_sclp_print_early(s);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -555,7 +555,6 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 | 
				
			||||||
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 | 
					CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 | 
				
			||||||
CONFIG_SLUB_DEBUG_ON=y
 | 
					CONFIG_SLUB_DEBUG_ON=y
 | 
				
			||||||
CONFIG_SLUB_STATS=y
 | 
					CONFIG_SLUB_STATS=y
 | 
				
			||||||
CONFIG_DEBUG_KMEMLEAK=y
 | 
					 | 
				
			||||||
CONFIG_DEBUG_STACK_USAGE=y
 | 
					CONFIG_DEBUG_STACK_USAGE=y
 | 
				
			||||||
CONFIG_DEBUG_VM=y
 | 
					CONFIG_DEBUG_VM=y
 | 
				
			||||||
CONFIG_DEBUG_VM_RB=y
 | 
					CONFIG_DEBUG_VM_RB=y
 | 
				
			||||||
| 
						 | 
					@ -563,6 +562,7 @@ CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 | 
				
			||||||
CONFIG_DEBUG_PER_CPU_MAPS=y
 | 
					CONFIG_DEBUG_PER_CPU_MAPS=y
 | 
				
			||||||
CONFIG_DEBUG_SHIRQ=y
 | 
					CONFIG_DEBUG_SHIRQ=y
 | 
				
			||||||
CONFIG_DETECT_HUNG_TASK=y
 | 
					CONFIG_DETECT_HUNG_TASK=y
 | 
				
			||||||
 | 
					CONFIG_PANIC_ON_OOPS=y
 | 
				
			||||||
CONFIG_TIMER_STATS=y
 | 
					CONFIG_TIMER_STATS=y
 | 
				
			||||||
CONFIG_DEBUG_RT_MUTEXES=y
 | 
					CONFIG_DEBUG_RT_MUTEXES=y
 | 
				
			||||||
CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
 | 
					CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -540,6 +540,7 @@ CONFIG_UNUSED_SYMBOLS=y
 | 
				
			||||||
CONFIG_MAGIC_SYSRQ=y
 | 
					CONFIG_MAGIC_SYSRQ=y
 | 
				
			||||||
CONFIG_DEBUG_KERNEL=y
 | 
					CONFIG_DEBUG_KERNEL=y
 | 
				
			||||||
CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 | 
					CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 | 
				
			||||||
 | 
					CONFIG_PANIC_ON_OOPS=y
 | 
				
			||||||
CONFIG_TIMER_STATS=y
 | 
					CONFIG_TIMER_STATS=y
 | 
				
			||||||
CONFIG_RCU_TORTURE_TEST=m
 | 
					CONFIG_RCU_TORTURE_TEST=m
 | 
				
			||||||
CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
					CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -537,6 +537,7 @@ CONFIG_FRAME_WARN=1024
 | 
				
			||||||
CONFIG_UNUSED_SYMBOLS=y
 | 
					CONFIG_UNUSED_SYMBOLS=y
 | 
				
			||||||
CONFIG_MAGIC_SYSRQ=y
 | 
					CONFIG_MAGIC_SYSRQ=y
 | 
				
			||||||
CONFIG_DEBUG_KERNEL=y
 | 
					CONFIG_DEBUG_KERNEL=y
 | 
				
			||||||
 | 
					CONFIG_PANIC_ON_OOPS=y
 | 
				
			||||||
CONFIG_TIMER_STATS=y
 | 
					CONFIG_TIMER_STATS=y
 | 
				
			||||||
CONFIG_RCU_TORTURE_TEST=m
 | 
					CONFIG_RCU_TORTURE_TEST=m
 | 
				
			||||||
CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
					CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,6 +71,7 @@ CONFIG_PRINTK_TIME=y
 | 
				
			||||||
CONFIG_DEBUG_INFO=y
 | 
					CONFIG_DEBUG_INFO=y
 | 
				
			||||||
CONFIG_DEBUG_FS=y
 | 
					CONFIG_DEBUG_FS=y
 | 
				
			||||||
CONFIG_DEBUG_KERNEL=y
 | 
					CONFIG_DEBUG_KERNEL=y
 | 
				
			||||||
 | 
					CONFIG_PANIC_ON_OOPS=y
 | 
				
			||||||
# CONFIG_SCHED_DEBUG is not set
 | 
					# CONFIG_SCHED_DEBUG is not set
 | 
				
			||||||
CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
					CONFIG_RCU_CPU_STALL_TIMEOUT=60
 | 
				
			||||||
# CONFIG_FTRACE is not set
 | 
					# CONFIG_FTRACE is not set
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
					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))) {
 | 
						if (unlikely(need_fallback(sctx->key_len))) {
 | 
				
			||||||
		crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
 | 
							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)
 | 
					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))) {
 | 
						if (unlikely(need_fallback(sctx->key_len))) {
 | 
				
			||||||
		crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
 | 
							crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,6 @@ CONFIG_IKCONFIG_PROC=y
 | 
				
			||||||
CONFIG_CGROUPS=y
 | 
					CONFIG_CGROUPS=y
 | 
				
			||||||
CONFIG_CPUSETS=y
 | 
					CONFIG_CPUSETS=y
 | 
				
			||||||
CONFIG_CGROUP_CPUACCT=y
 | 
					CONFIG_CGROUP_CPUACCT=y
 | 
				
			||||||
CONFIG_RESOURCE_COUNTERS=y
 | 
					 | 
				
			||||||
CONFIG_MEMCG=y
 | 
					CONFIG_MEMCG=y
 | 
				
			||||||
CONFIG_MEMCG_SWAP=y
 | 
					CONFIG_MEMCG_SWAP=y
 | 
				
			||||||
CONFIG_CGROUP_SCHED=y
 | 
					CONFIG_CGROUP_SCHED=y
 | 
				
			||||||
| 
						 | 
					@ -22,12 +21,8 @@ CONFIG_RT_GROUP_SCHED=y
 | 
				
			||||||
CONFIG_BLK_CGROUP=y
 | 
					CONFIG_BLK_CGROUP=y
 | 
				
			||||||
CONFIG_NAMESPACES=y
 | 
					CONFIG_NAMESPACES=y
 | 
				
			||||||
CONFIG_BLK_DEV_INITRD=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_EXPERT=y
 | 
				
			||||||
 | 
					CONFIG_BPF_SYSCALL=y
 | 
				
			||||||
# CONFIG_COMPAT_BRK is not set
 | 
					# CONFIG_COMPAT_BRK is not set
 | 
				
			||||||
CONFIG_PROFILING=y
 | 
					CONFIG_PROFILING=y
 | 
				
			||||||
CONFIG_OPROFILE=y
 | 
					CONFIG_OPROFILE=y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,3 +5,4 @@
 | 
				
			||||||
obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 | 
					obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
 | 
					s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
 | 
				
			||||||
 | 
					s390_hypfs-objs += hypfs_diag0c.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,10 @@ extern int hypfs_vm_init(void);
 | 
				
			||||||
extern void hypfs_vm_exit(void);
 | 
					extern void hypfs_vm_exit(void);
 | 
				
			||||||
extern int hypfs_vm_create_files(struct dentry *root);
 | 
					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 */
 | 
					/* Set Partition-Resource Parameter */
 | 
				
			||||||
int hypfs_sprp_init(void);
 | 
					int hypfs_sprp_init(void);
 | 
				
			||||||
void hypfs_sprp_exit(void);
 | 
					void hypfs_sprp_exit(void);
 | 
				
			||||||
| 
						 | 
					@ -49,7 +53,6 @@ struct hypfs_dbfs_data {
 | 
				
			||||||
	void			*buf_free_ptr;
 | 
						void			*buf_free_ptr;
 | 
				
			||||||
	size_t			size;
 | 
						size_t			size;
 | 
				
			||||||
	struct hypfs_dbfs_file	*dbfs_file;
 | 
						struct hypfs_dbfs_file	*dbfs_file;
 | 
				
			||||||
	struct kref		kref;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hypfs_dbfs_file {
 | 
					struct hypfs_dbfs_file {
 | 
				
			||||||
| 
						 | 
					@ -61,8 +64,6 @@ struct hypfs_dbfs_file {
 | 
				
			||||||
					   unsigned long);
 | 
										   unsigned long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Private data for hypfs_dbfs.c */
 | 
						/* Private data for hypfs_dbfs.c */
 | 
				
			||||||
	struct hypfs_dbfs_data	*data;
 | 
					 | 
				
			||||||
	struct delayed_work	data_free_work;
 | 
					 | 
				
			||||||
	struct mutex		lock;
 | 
						struct mutex		lock;
 | 
				
			||||||
	struct dentry		*dentry;
 | 
						struct dentry		*dentry;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,33 +17,16 @@ static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
 | 
				
			||||||
	data = kmalloc(sizeof(*data), GFP_KERNEL);
 | 
						data = kmalloc(sizeof(*data), GFP_KERNEL);
 | 
				
			||||||
	if (!data)
 | 
						if (!data)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	kref_init(&data->kref);
 | 
					 | 
				
			||||||
	data->dbfs_file = f;
 | 
						data->dbfs_file = f;
 | 
				
			||||||
	return data;
 | 
						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);
 | 
						data->dbfs_file->data_free(data->buf_free_ptr);
 | 
				
			||||||
	kfree(data);
 | 
						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,
 | 
					static ssize_t dbfs_read(struct file *file, char __user *buf,
 | 
				
			||||||
			 size_t size, loff_t *ppos)
 | 
								 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;
 | 
						df = file_inode(file)->i_private;
 | 
				
			||||||
	mutex_lock(&df->lock);
 | 
						mutex_lock(&df->lock);
 | 
				
			||||||
	if (!df->data) {
 | 
					 | 
				
			||||||
	data = hypfs_dbfs_data_alloc(df);
 | 
						data = hypfs_dbfs_data_alloc(df);
 | 
				
			||||||
	if (!data) {
 | 
						if (!data) {
 | 
				
			||||||
		mutex_unlock(&df->lock);
 | 
							mutex_unlock(&df->lock);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		rc = df->data_create(&data->buf, &data->buf_free_ptr,
 | 
						rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size);
 | 
				
			||||||
				     &data->size);
 | 
					 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		mutex_unlock(&df->lock);
 | 
							mutex_unlock(&df->lock);
 | 
				
			||||||
		kfree(data);
 | 
							kfree(data);
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		df->data = data;
 | 
					 | 
				
			||||||
		schedule_delayed_work(&df->data_free_work, HZ);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	data = df->data;
 | 
					 | 
				
			||||||
	kref_get(&data->kref);
 | 
					 | 
				
			||||||
	mutex_unlock(&df->lock);
 | 
						mutex_unlock(&df->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
 | 
						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;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,7 +84,6 @@ int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
 | 
				
			||||||
	if (IS_ERR(df->dentry))
 | 
						if (IS_ERR(df->dentry))
 | 
				
			||||||
		return PTR_ERR(df->dentry);
 | 
							return PTR_ERR(df->dentry);
 | 
				
			||||||
	mutex_init(&df->lock);
 | 
						mutex_init(&df->lock);
 | 
				
			||||||
	INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										139
									
								
								arch/s390/hypfs/hypfs_diag0c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								arch/s390/hypfs/hypfs_diag0c.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -482,10 +482,14 @@ static int __init hypfs_init(void)
 | 
				
			||||||
		rc = -ENODATA;
 | 
							rc = -ENODATA;
 | 
				
			||||||
		goto fail_hypfs_vm_exit;
 | 
							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);
 | 
						s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
 | 
				
			||||||
	if (!s390_kobj) {
 | 
						if (!s390_kobj) {
 | 
				
			||||||
		rc = -ENOMEM;
 | 
							rc = -ENOMEM;
 | 
				
			||||||
		goto fail_hypfs_sprp_exit;
 | 
							goto fail_hypfs_diag0c_exit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc = register_filesystem(&hypfs_type);
 | 
						rc = register_filesystem(&hypfs_type);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
| 
						 | 
					@ -494,6 +498,8 @@ static int __init hypfs_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail_filesystem:
 | 
					fail_filesystem:
 | 
				
			||||||
	kobject_put(s390_kobj);
 | 
						kobject_put(s390_kobj);
 | 
				
			||||||
 | 
					fail_hypfs_diag0c_exit:
 | 
				
			||||||
 | 
						hypfs_diag0c_exit();
 | 
				
			||||||
fail_hypfs_sprp_exit:
 | 
					fail_hypfs_sprp_exit:
 | 
				
			||||||
	hypfs_sprp_exit();
 | 
						hypfs_sprp_exit();
 | 
				
			||||||
fail_hypfs_vm_exit:
 | 
					fail_hypfs_vm_exit:
 | 
				
			||||||
| 
						 | 
					@ -510,6 +516,7 @@ static void __exit hypfs_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unregister_filesystem(&hypfs_type);
 | 
						unregister_filesystem(&hypfs_type);
 | 
				
			||||||
	kobject_put(s390_kobj);
 | 
						kobject_put(s390_kobj);
 | 
				
			||||||
 | 
						hypfs_diag0c_exit();
 | 
				
			||||||
	hypfs_sprp_exit();
 | 
						hypfs_sprp_exit();
 | 
				
			||||||
	hypfs_vm_exit();
 | 
						hypfs_vm_exit();
 | 
				
			||||||
	hypfs_diag_exit();
 | 
						hypfs_diag_exit();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val)
 | 
				
			||||||
	return cc;
 | 
						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 */
 | 
					/* Query sampling information */
 | 
				
			||||||
static inline int qsi(struct hws_qsi_info_block *info)
 | 
					static inline int qsi(struct hws_qsi_info_block *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					   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.  */
 | 
					   that it will "exec", and that there is sufficient room for the brk.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern unsigned long randomize_et_dyn(unsigned long base);
 | 
					extern unsigned long randomize_et_dyn(void);
 | 
				
			||||||
#define ELF_ET_DYN_BASE		(randomize_et_dyn(STACK_TOP / 3 * 2))
 | 
					#define ELF_ET_DYN_BASE		randomize_et_dyn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This yields a mask that user programs can use to figure out what
 | 
					/* This yields a mask that user programs can use to figure out what
 | 
				
			||||||
   instruction set this CPU supports. */
 | 
					   instruction set this CPU supports. */
 | 
				
			||||||
| 
						 | 
					@ -209,7 +209,9 @@ do {								\
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
#endif /* CONFIG_COMPAT */
 | 
					#endif /* CONFIG_COMPAT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STACK_RND_MASK	0x7ffUL
 | 
					extern unsigned long mmap_rnd_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STACK_RND_MASK	(mmap_rnd_mask)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ARCH_DLINFO							    \
 | 
					#define ARCH_DLINFO							    \
 | 
				
			||||||
do {									    \
 | 
					do {									    \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
 | 
					#define ARCH_SUPPORTS_FTRACE_OPS 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CC_USING_HOTPATCH
 | 
				
			||||||
 | 
					#define MCOUNT_INSN_SIZE	6
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
#define MCOUNT_INSN_SIZE	24
 | 
					#define MCOUNT_INSN_SIZE	24
 | 
				
			||||||
#define MCOUNT_RETURN_FIXUP	18
 | 
					#define MCOUNT_RETURN_FIXUP	18
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __ASSEMBLY__
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,17 +41,28 @@ struct ftrace_insn {
 | 
				
			||||||
static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
 | 
					static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_FUNCTION_TRACER
 | 
					#ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
 | 
					#ifdef CC_USING_HOTPATCH
 | 
				
			||||||
 | 
						/* brcl 0,0 */
 | 
				
			||||||
 | 
						insn->opc = 0xc004;
 | 
				
			||||||
 | 
						insn->disp = 0;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
	/* jg .+24 */
 | 
						/* jg .+24 */
 | 
				
			||||||
	insn->opc = 0xc0f4;
 | 
						insn->opc = 0xc0f4;
 | 
				
			||||||
	insn->disp = MCOUNT_INSN_SIZE / 2;
 | 
						insn->disp = MCOUNT_INSN_SIZE / 2;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int is_ftrace_nop(struct ftrace_insn *insn)
 | 
					static inline int is_ftrace_nop(struct ftrace_insn *insn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_FUNCTION_TRACER
 | 
					#ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
 | 
					#ifdef CC_USING_HOTPATCH
 | 
				
			||||||
 | 
						if (insn->disp == 0)
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
	if (insn->disp == MCOUNT_INSN_SIZE / 2)
 | 
						if (insn->disp == MCOUNT_INSN_SIZE / 2)
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define JUMP_LABEL_NOP_SIZE 6
 | 
					#define JUMP_LABEL_NOP_SIZE 6
 | 
				
			||||||
 | 
					#define JUMP_LABEL_NOP_OFFSET 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_64BIT
 | 
					#ifdef CONFIG_64BIT
 | 
				
			||||||
#define ASM_PTR ".quad"
 | 
					#define ASM_PTR ".quad"
 | 
				
			||||||
| 
						 | 
					@ -13,9 +14,13 @@
 | 
				
			||||||
#define ASM_ALIGN ".balign 4"
 | 
					#define ASM_ALIGN ".balign 4"
 | 
				
			||||||
#endif
 | 
					#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)
 | 
					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"
 | 
							".pushsection __jump_table, \"aw\"\n"
 | 
				
			||||||
		ASM_ALIGN "\n"
 | 
							ASM_ALIGN "\n"
 | 
				
			||||||
		ASM_PTR " 0b, %l[label], %0\n"
 | 
							ASM_PTR " 0b, %l[label], %0\n"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1758,6 +1758,10 @@ extern int s390_enable_sie(void);
 | 
				
			||||||
extern int s390_enable_skey(void);
 | 
					extern int s390_enable_skey(void);
 | 
				
			||||||
extern void s390_reset_cmma(struct mm_struct *mm);
 | 
					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
 | 
					 * No page table caches to initialise
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -215,10 +215,7 @@ static inline unsigned short stap(void)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Give up the time slice of the virtual PU.
 | 
					 * Give up the time slice of the virtual PU.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline void cpu_relax(void)
 | 
					void cpu_relax(void);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	barrier();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define cpu_relax_lowlatency()  barrier()
 | 
					#define cpu_relax_lowlatency()  barrier()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,5 +15,6 @@ struct reset_call {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void register_reset_call(struct reset_call *reset);
 | 
					extern void register_reset_call(struct reset_call *reset);
 | 
				
			||||||
extern void unregister_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 */
 | 
					#endif /* _ASM_S390_RESET_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ struct sclp_ipl_info {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sclp_cpu_entry {
 | 
					struct sclp_cpu_entry {
 | 
				
			||||||
	u8 address;
 | 
						u8 core_id;
 | 
				
			||||||
	u8 reserved0[2];
 | 
						u8 reserved0[2];
 | 
				
			||||||
	u8 : 3;
 | 
						u8 : 3;
 | 
				
			||||||
	u8 siif : 1;
 | 
						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_rnmax(void);
 | 
				
			||||||
unsigned long long sclp_get_rzm(void);
 | 
					unsigned long long sclp_get_rzm(void);
 | 
				
			||||||
unsigned int sclp_get_max_cpu(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_blk_count(void);
 | 
				
			||||||
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
 | 
					int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
 | 
				
			||||||
int sclp_chp_configure(struct chp_id chpid);
 | 
					int sclp_chp_configure(struct chp_id chpid);
 | 
				
			||||||
| 
						 | 
					@ -68,4 +71,6 @@ void sclp_early_detect(void);
 | 
				
			||||||
int sclp_has_siif(void);
 | 
					int sclp_has_siif(void);
 | 
				
			||||||
unsigned int sclp_get_ibc(void);
 | 
					unsigned int sclp_get_ibc(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					long _sclp_print_early(const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_S390_SCLP_H */
 | 
					#endif /* _ASM_S390_SCLP_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ extern void detect_memory_memblock(void);
 | 
				
			||||||
#define MACHINE_FLAG_TE		(1UL << 15)
 | 
					#define MACHINE_FLAG_TE		(1UL << 15)
 | 
				
			||||||
#define MACHINE_FLAG_TLB_LC	(1UL << 17)
 | 
					#define MACHINE_FLAG_TLB_LC	(1UL << 17)
 | 
				
			||||||
#define MACHINE_FLAG_VX		(1UL << 18)
 | 
					#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_VM		(S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 | 
				
			||||||
#define MACHINE_IS_KVM		(S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
 | 
					#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_TE		(0)
 | 
				
			||||||
#define MACHINE_HAS_TLB_LC	(0)
 | 
					#define MACHINE_HAS_TLB_LC	(0)
 | 
				
			||||||
#define MACHINE_HAS_VX		(0)
 | 
					#define MACHINE_HAS_VX		(0)
 | 
				
			||||||
 | 
					#define MACHINE_HAS_CAD		(0)
 | 
				
			||||||
#else /* CONFIG_64BIT */
 | 
					#else /* CONFIG_64BIT */
 | 
				
			||||||
#define MACHINE_HAS_IEEE	(1)
 | 
					#define MACHINE_HAS_IEEE	(1)
 | 
				
			||||||
#define MACHINE_HAS_CSP		(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_TE		(S390_lowcore.machine_flags & MACHINE_FLAG_TE)
 | 
				
			||||||
#define MACHINE_HAS_TLB_LC	(S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
 | 
					#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_VX		(S390_lowcore.machine_flags & MACHINE_FLAG_VX)
 | 
				
			||||||
 | 
					#define MACHINE_HAS_CAD		(S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
 | 
				
			||||||
#endif /* CONFIG_64BIT */
 | 
					#endif /* CONFIG_64BIT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#define SIGP_SET_ARCHITECTURE	     18
 | 
					#define SIGP_SET_ARCHITECTURE	     18
 | 
				
			||||||
#define SIGP_COND_EMERGENCY_SIGNAL   19
 | 
					#define SIGP_COND_EMERGENCY_SIGNAL   19
 | 
				
			||||||
#define SIGP_SENSE_RUNNING	     21
 | 
					#define SIGP_SENSE_RUNNING	     21
 | 
				
			||||||
 | 
					#define SIGP_SET_MULTI_THREADING     22
 | 
				
			||||||
#define SIGP_STORE_ADDITIONAL_STATUS 23
 | 
					#define SIGP_STORE_ADDITIONAL_STATUS 23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SIGP condition codes */
 | 
					/* SIGP condition codes */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,8 @@
 | 
				
			||||||
#define raw_smp_processor_id()	(S390_lowcore.cpu_nr)
 | 
					#define raw_smp_processor_id()	(S390_lowcore.cpu_nr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct mutex smp_cpu_state_mutex;
 | 
					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);
 | 
					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 */
 | 
					#else /* CONFIG_SMP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define smp_cpu_mtid	0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
 | 
					static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	func(data);
 | 
						func(data);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,11 @@ struct sysinfo_2_2_2 {
 | 
				
			||||||
	unsigned short cpus_reserved;
 | 
						unsigned short cpus_reserved;
 | 
				
			||||||
	char name[8];
 | 
						char name[8];
 | 
				
			||||||
	unsigned int caf;
 | 
						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_dedicated;
 | 
				
			||||||
	unsigned short cpus_shared;
 | 
						unsigned short cpus_shared;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -120,26 +124,28 @@ struct sysinfo_3_2_2 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int topology_max_mnest;
 | 
					extern int topology_max_mnest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TOPOLOGY_CPU_BITS	64
 | 
					#define TOPOLOGY_CORE_BITS	64
 | 
				
			||||||
#define TOPOLOGY_NR_MAG		6
 | 
					#define TOPOLOGY_NR_MAG		6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct topology_cpu {
 | 
					struct topology_core {
 | 
				
			||||||
	unsigned char reserved0[4];
 | 
						unsigned char nl;
 | 
				
			||||||
 | 
						unsigned char reserved0[3];
 | 
				
			||||||
	unsigned char :6;
 | 
						unsigned char :6;
 | 
				
			||||||
	unsigned char pp:2;
 | 
						unsigned char pp:2;
 | 
				
			||||||
	unsigned char reserved1;
 | 
						unsigned char reserved1;
 | 
				
			||||||
	unsigned short origin;
 | 
						unsigned short origin;
 | 
				
			||||||
	unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
 | 
						unsigned long mask[TOPOLOGY_CORE_BITS / BITS_PER_LONG];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct topology_container {
 | 
					struct topology_container {
 | 
				
			||||||
	unsigned char reserved[7];
 | 
						unsigned char nl;
 | 
				
			||||||
 | 
						unsigned char reserved[6];
 | 
				
			||||||
	unsigned char id;
 | 
						unsigned char id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
union topology_entry {
 | 
					union topology_entry {
 | 
				
			||||||
	unsigned char nl;
 | 
						unsigned char nl;
 | 
				
			||||||
	struct topology_cpu cpu;
 | 
						struct topology_core cpu;
 | 
				
			||||||
	struct topology_container container;
 | 
						struct topology_container container;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,11 @@ struct cpu;
 | 
				
			||||||
#ifdef CONFIG_SCHED_BOOK
 | 
					#ifdef CONFIG_SCHED_BOOK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cpu_topology_s390 {
 | 
					struct cpu_topology_s390 {
 | 
				
			||||||
 | 
						unsigned short thread_id;
 | 
				
			||||||
	unsigned short core_id;
 | 
						unsigned short core_id;
 | 
				
			||||||
	unsigned short socket_id;
 | 
						unsigned short socket_id;
 | 
				
			||||||
	unsigned short book_id;
 | 
						unsigned short book_id;
 | 
				
			||||||
 | 
						cpumask_t thread_mask;
 | 
				
			||||||
	cpumask_t core_mask;
 | 
						cpumask_t core_mask;
 | 
				
			||||||
	cpumask_t book_mask;
 | 
						cpumask_t book_mask;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -19,6 +21,8 @@ struct cpu_topology_s390 {
 | 
				
			||||||
extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
 | 
					extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define topology_physical_package_id(cpu)	(cpu_topology[cpu].socket_id)
 | 
					#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_id(cpu)			(cpu_topology[cpu].core_id)
 | 
				
			||||||
#define topology_core_cpumask(cpu)		(&cpu_topology[cpu].core_mask)
 | 
					#define topology_core_cpumask(cpu)		(&cpu_topology[cpu].core_mask)
 | 
				
			||||||
#define topology_book_id(cpu)			(cpu_topology[cpu].book_id)
 | 
					#define topology_book_id(cpu)			(cpu_topology[cpu].book_id)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,19 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * IOCTL interface for hypfs
 | 
					 * Structures for hypfs interface
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright IBM Corp. 2013
 | 
					 * Copyright IBM Corp. 2013
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
 | 
					 * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _ASM_HYPFS_CTL_H
 | 
					#ifndef _ASM_HYPFS_H
 | 
				
			||||||
#define _ASM_HYPFS_CTL_H
 | 
					#define _ASM_HYPFS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * IOCTL for binary interface /sys/kernel/debug/diag_304
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
struct hypfs_diag304 {
 | 
					struct hypfs_diag304 {
 | 
				
			||||||
	__u32	args[2];
 | 
						__u32	args[2];
 | 
				
			||||||
	__u64	data;
 | 
						__u64	data;
 | 
				
			||||||
| 
						 | 
					@ -22,4 +25,30 @@ struct hypfs_diag304 {
 | 
				
			||||||
#define HYPFS_DIAG304 \
 | 
					#define HYPFS_DIAG304 \
 | 
				
			||||||
	_IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct 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
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
# Don't trace early setup code and tracing code
 | 
					# Don't trace early setup code and tracing code
 | 
				
			||||||
CFLAGS_REMOVE_early.o = -pg
 | 
					CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
CFLAGS_REMOVE_ftrace.o = -pg
 | 
					CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,7 +97,8 @@ ENTRY(diag308_reset)
 | 
				
			||||||
	lg	%r4,0(%r4)		# Save PSW
 | 
						lg	%r4,0(%r4)		# Save PSW
 | 
				
			||||||
	sturg	%r4,%r3			# Use sturg, because of large pages
 | 
						sturg	%r4,%r3			# Use sturg, because of large pages
 | 
				
			||||||
	lghi	%r1,1
 | 
						lghi	%r1,1
 | 
				
			||||||
	diag	%r1,%r1,0x308
 | 
						lghi	%r0,0
 | 
				
			||||||
 | 
						diag	%r0,%r1,0x308
 | 
				
			||||||
.Lrestart_part2:
 | 
					.Lrestart_part2:
 | 
				
			||||||
	lhi	%r0,0			# Load r0 with zero
 | 
						lhi	%r0,0			# Load r0 with zero
 | 
				
			||||||
	lhi	%r1,2			# Use mode 2 = ESAME (dump)
 | 
						lhi	%r1,2			# Use mode 2 = ESAME (dump)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,37 +5,11 @@
 | 
				
			||||||
 *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
 | 
					 *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/notifier.h>
 | 
					 | 
				
			||||||
#include <linux/seq_file.h>
 | 
					#include <linux/seq_file.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/list.h>
 | 
					 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/cpu.h>
 | 
					#include <linux/cpu.h>
 | 
				
			||||||
 | 
					#include <linux/cacheinfo.h>
 | 
				
			||||||
#include <asm/facility.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 {
 | 
					enum {
 | 
				
			||||||
	CACHE_SCOPE_NOTEXISTS,
 | 
						CACHE_SCOPE_NOTEXISTS,
 | 
				
			||||||
	CACHE_SCOPE_PRIVATE,
 | 
						CACHE_SCOPE_PRIVATE,
 | 
				
			||||||
| 
						 | 
					@ -44,10 +18,10 @@ enum {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	CACHE_TYPE_SEPARATE,
 | 
						CTYPE_SEPARATE,
 | 
				
			||||||
	CACHE_TYPE_DATA,
 | 
						CTYPE_DATA,
 | 
				
			||||||
	CACHE_TYPE_INSTRUCTION,
 | 
						CTYPE_INSTRUCTION,
 | 
				
			||||||
	CACHE_TYPE_UNIFIED,
 | 
						CTYPE_UNIFIED,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
| 
						 | 
					@ -70,37 +44,60 @@ struct cache_info {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CACHE_MAX_LEVEL 8
 | 
					#define CACHE_MAX_LEVEL 8
 | 
				
			||||||
 | 
					 | 
				
			||||||
union cache_topology {
 | 
					union cache_topology {
 | 
				
			||||||
	struct cache_info ci[CACHE_MAX_LEVEL];
 | 
						struct cache_info ci[CACHE_MAX_LEVEL];
 | 
				
			||||||
	unsigned long long raw;
 | 
						unsigned long long raw;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char * const cache_type_string[] = {
 | 
					static const char * const cache_type_string[] = {
 | 
				
			||||||
	"Data",
 | 
						"",
 | 
				
			||||||
	"Instruction",
 | 
						"Instruction",
 | 
				
			||||||
 | 
						"Data",
 | 
				
			||||||
 | 
						"",
 | 
				
			||||||
	"Unified",
 | 
						"Unified",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cache_dir *cache_dir_cpu[NR_CPUS];
 | 
					static const enum cache_type cache_type_map[] = {
 | 
				
			||||||
static LIST_HEAD(cache_list);
 | 
						[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)
 | 
					void show_cacheinfo(struct seq_file *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cache *cache;
 | 
						struct cpu_cacheinfo *this_cpu_ci;
 | 
				
			||||||
	int index = 0;
 | 
						struct cacheinfo *cache;
 | 
				
			||||||
 | 
						int idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(cache, &cache_list, list) {
 | 
						get_online_cpus();
 | 
				
			||||||
		seq_printf(m, "cache%-11d: ", index);
 | 
						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, "level=%d ", cache->level);
 | 
				
			||||||
		seq_printf(m, "type=%s ", cache_type_string[cache->type]);
 | 
							seq_printf(m, "type=%s ", cache_type_string[cache->type]);
 | 
				
			||||||
		seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared");
 | 
							seq_printf(m, "scope=%s ",
 | 
				
			||||||
		seq_printf(m, "size=%luK ", cache->size >> 10);
 | 
								   cache->disable_sysfs ? "Shared" : "Private");
 | 
				
			||||||
		seq_printf(m, "line_size=%u ", cache->line_size);
 | 
							seq_printf(m, "size=%dK ", cache->size >> 10);
 | 
				
			||||||
		seq_printf(m, "associativity=%d", cache->associativity);
 | 
							seq_printf(m, "line_size=%u ", cache->coherency_line_size);
 | 
				
			||||||
 | 
							seq_printf(m, "associativity=%d", cache->ways_of_associativity);
 | 
				
			||||||
		seq_puts(m, "\n");
 | 
							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)
 | 
					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;
 | 
						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, num_sets;
 | 
				
			||||||
	int ti;
 | 
						int cpu = smp_processor_id();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cache = kzalloc(sizeof(*cache), GFP_KERNEL);
 | 
						if (type == CACHE_TYPE_INST)
 | 
				
			||||||
	if (!cache)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	if (type == CACHE_TYPE_INSTRUCTION)
 | 
					 | 
				
			||||||
		ti = CACHE_TI_INSTRUCTION;
 | 
							ti = CACHE_TI_INSTRUCTION;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		ti = CACHE_TI_UNIFIED;
 | 
							ti = CACHE_TI_UNIFIED;
 | 
				
			||||||
	cache->size = ecag(EXTRACT_SIZE, level, ti);
 | 
					
 | 
				
			||||||
	cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
 | 
						this_leaf->level = level + 1;
 | 
				
			||||||
	cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti);
 | 
						this_leaf->type = type;
 | 
				
			||||||
	cache->nr_sets = cache->size / cache->associativity;
 | 
						this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti);
 | 
				
			||||||
	cache->nr_sets /= cache->line_size;
 | 
						this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY,
 | 
				
			||||||
	cache->private = private;
 | 
											level, ti);
 | 
				
			||||||
	cache->level = level + 1;
 | 
						this_leaf->size = ecag(EXTRACT_SIZE, level, ti);
 | 
				
			||||||
	cache->type = type - 1;
 | 
					
 | 
				
			||||||
	list_add_tail(&cache->list, &cache_list);
 | 
						num_sets = this_leaf->size / this_leaf->coherency_line_size;
 | 
				
			||||||
	return 0;
 | 
						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 void __init cache_build_info(void)
 | 
					int init_cache_level(unsigned int cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cache *cache, *next;
 | 
						struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 | 
				
			||||||
 | 
						unsigned int level = 0, leaves = 0;
 | 
				
			||||||
	union cache_topology ct;
 | 
						union cache_topology ct;
 | 
				
			||||||
	int level, private, rc;
 | 
						enum cache_type ctype;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!this_cpu_ci)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
 | 
						ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
 | 
				
			||||||
	for (level = 0; level < CACHE_MAX_LEVEL; level++) {
 | 
						do {
 | 
				
			||||||
		switch (ct.ci[level].scope) {
 | 
							ctype = get_cache_type(&ct.ci[0], level);
 | 
				
			||||||
		case CACHE_SCOPE_SHARED:
 | 
							if (ctype == CACHE_TYPE_NOCACHE)
 | 
				
			||||||
			private = 0;
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case CACHE_SCOPE_PRIVATE:
 | 
							/* Separate instruction and data caches */
 | 
				
			||||||
			private = 1;
 | 
							leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
 | 
				
			||||||
			break;
 | 
						} while (++level < CACHE_MAX_LEVEL);
 | 
				
			||||||
		default:
 | 
					
 | 
				
			||||||
			return;
 | 
						this_cpu_ci->num_levels = level;
 | 
				
			||||||
 | 
						this_cpu_ci->num_leaves = leaves;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		if (ct.ci[level].type == CACHE_TYPE_SEPARATE) {
 | 
					
 | 
				
			||||||
			rc  = cache_add(level, private, CACHE_TYPE_DATA);
 | 
					int populate_cache_leaves(unsigned int cpu)
 | 
				
			||||||
			rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION);
 | 
					{
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 {
 | 
							} else {
 | 
				
			||||||
			rc = cache_add(level, private, ct.ci[level].type);
 | 
								ci_leaf_init(this_leaf++, pvt, ctype, level);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int cache_add_cpu(int cpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct cache_dir *cache_dir;
 | 
					 | 
				
			||||||
	struct cache *cache;
 | 
					 | 
				
			||||||
	int rc, index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		rc = cache_create_index_dir(cache_dir, cache, index, cpu);
 | 
					 | 
				
			||||||
		if (rc)
 | 
					 | 
				
			||||||
			return rc;
 | 
					 | 
				
			||||||
		index++;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void cache_remove_cpu(int cpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct cache_index_dir *index, *next;
 | 
					 | 
				
			||||||
	struct cache_dir *cache_dir;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int cache_hotplug(struct notifier_block *nfb, unsigned long action,
 | 
					 | 
				
			||||||
			 void *hcpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int cpu = (long)hcpu;
 | 
					 | 
				
			||||||
	int rc = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,7 +137,7 @@ enum {
 | 
				
			||||||
	INSTR_RSI_RRP,
 | 
						INSTR_RSI_RRP,
 | 
				
			||||||
	INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
 | 
						INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
 | 
				
			||||||
	INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
 | 
						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_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
 | 
				
			||||||
	INSTR_RS_RURD,
 | 
						INSTR_RS_RURD,
 | 
				
			||||||
	INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
 | 
						INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
 | 
				
			||||||
| 
						 | 
					@ -226,7 +226,6 @@ static const struct s390_operand operands[] =
 | 
				
			||||||
	[U16_32] = { 16, 32, 0 },
 | 
						[U16_32] = { 16, 32, 0 },
 | 
				
			||||||
	[J16_16] = { 16, 16, OPERAND_PCREL },
 | 
						[J16_16] = { 16, 16, OPERAND_PCREL },
 | 
				
			||||||
	[J16_32] = { 16, 32, OPERAND_PCREL },
 | 
						[J16_32] = { 16, 32, OPERAND_PCREL },
 | 
				
			||||||
	[I16_32] = { 16, 32, OPERAND_SIGNED },
 | 
					 | 
				
			||||||
	[I24_24] = { 24, 24, OPERAND_SIGNED },
 | 
						[I24_24] = { 24, 24, OPERAND_SIGNED },
 | 
				
			||||||
	[J32_16] = { 32, 16, OPERAND_PCREL },
 | 
						[J32_16] = { 32, 16, OPERAND_PCREL },
 | 
				
			||||||
	[I32_16] = { 32, 16, OPERAND_SIGNED },
 | 
						[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_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_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_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_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_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 },
 | 
						[INSTR_RS_AARD]	  = { 0xff, A_8,A_12,D_20,B_16,0,0 },
 | 
				
			||||||
| 
						 | 
					@ -451,7 +451,8 @@ enum {
 | 
				
			||||||
	LONG_INSN_VERLLV,
 | 
						LONG_INSN_VERLLV,
 | 
				
			||||||
	LONG_INSN_VESRAV,
 | 
						LONG_INSN_VESRAV,
 | 
				
			||||||
	LONG_INSN_VESRLV,
 | 
						LONG_INSN_VESRLV,
 | 
				
			||||||
	LONG_INSN_VSBCBI
 | 
						LONG_INSN_VSBCBI,
 | 
				
			||||||
 | 
						LONG_INSN_STCCTM
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *long_insn_name[] = {
 | 
					static char *long_insn_name[] = {
 | 
				
			||||||
| 
						 | 
					@ -531,6 +532,7 @@ static char *long_insn_name[] = {
 | 
				
			||||||
	[LONG_INSN_VESRAV] = "vesrav",
 | 
						[LONG_INSN_VESRAV] = "vesrav",
 | 
				
			||||||
	[LONG_INSN_VESRLV] = "vesrlv",
 | 
						[LONG_INSN_VESRLV] = "vesrlv",
 | 
				
			||||||
	[LONG_INSN_VSBCBI] = "vsbcbi",
 | 
						[LONG_INSN_VSBCBI] = "vsbcbi",
 | 
				
			||||||
 | 
						[LONG_INSN_STCCTM] = "stcctm",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct s390_insn opcode[] = {
 | 
					static struct s390_insn opcode[] = {
 | 
				
			||||||
| 
						 | 
					@ -1656,6 +1658,7 @@ static struct s390_insn opcode_eb[] = {
 | 
				
			||||||
	{ "lric", 0x60, INSTR_RSY_RDRM },
 | 
						{ "lric", 0x60, INSTR_RSY_RDRM },
 | 
				
			||||||
	{ "stric", 0x61, INSTR_RSY_RDRM },
 | 
						{ "stric", 0x61, INSTR_RSY_RDRM },
 | 
				
			||||||
	{ "mric", 0x62, INSTR_RSY_RDRM },
 | 
						{ "mric", 0x62, INSTR_RSY_RDRM },
 | 
				
			||||||
 | 
						{ { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD },
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	{ "rll", 0x1d, INSTR_RSY_RRRD },
 | 
						{ "rll", 0x1d, INSTR_RSY_RRRD },
 | 
				
			||||||
	{ "mvclu", 0x8e, INSTR_RSY_RRRD },
 | 
						{ "mvclu", 0x8e, INSTR_RSY_RRRD },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,9 +393,27 @@ static __init void detect_machine_facilities(void)
 | 
				
			||||||
		S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
 | 
							S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
 | 
				
			||||||
	if (test_facility(129))
 | 
						if (test_facility(129))
 | 
				
			||||||
		S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
 | 
							S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
 | 
				
			||||||
 | 
						if (test_facility(128))
 | 
				
			||||||
 | 
							S390_lowcore.machine_flags |= MACHINE_FLAG_CAD;
 | 
				
			||||||
#endif
 | 
					#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)
 | 
					static __init void rescue_initrd(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_BLK_DEV_INITRD
 | 
					#ifdef CONFIG_BLK_DEV_INITRD
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,9 +71,11 @@ struct s390_mmap_arg_struct;
 | 
				
			||||||
struct fadvise64_64_args;
 | 
					struct fadvise64_64_args;
 | 
				
			||||||
struct old_sigaction;
 | 
					struct old_sigaction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					long sys_rt_sigreturn(void);
 | 
				
			||||||
 | 
					long sys_sigreturn(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
long sys_s390_personality(unsigned int personality);
 | 
					long sys_s390_personality(unsigned int personality);
 | 
				
			||||||
long sys_s390_runtime_instr(int command, int signum);
 | 
					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_write(unsigned long, const void __user *, size_t);
 | 
				
			||||||
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
 | 
					long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
 | 
				
			||||||
#endif /* _ENTRY_H */
 | 
					#endif /* _ENTRY_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,13 @@
 | 
				
			||||||
 *	lg	%r14,8(%r15)		# offset 18
 | 
					 *	lg	%r14,8(%r15)		# offset 18
 | 
				
			||||||
 * The jg instruction branches to offset 24 to skip as many instructions
 | 
					 * The jg instruction branches to offset 24 to skip as many instructions
 | 
				
			||||||
 * as possible.
 | 
					 * 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;
 | 
					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,
 | 
					int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 | 
				
			||||||
		    unsigned long addr)
 | 
							    unsigned long addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ftrace_insn insn;
 | 
						struct ftrace_insn orig, new, old;
 | 
				
			||||||
	unsigned short op;
 | 
					 | 
				
			||||||
	void *from, *to;
 | 
					 | 
				
			||||||
	size_t size;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ftrace_generate_nop_insn(&insn);
 | 
						if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
 | 
				
			||||||
	size = sizeof(insn);
 | 
					 | 
				
			||||||
	from = &insn;
 | 
					 | 
				
			||||||
	to = (void *) rec->ip;
 | 
					 | 
				
			||||||
	if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
 | 
					 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
						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
 | 
							 * If we find a breakpoint instruction, a kprobe has been
 | 
				
			||||||
	 * at the beginning of the function. We write the constant
 | 
							 * placed at the beginning of the function. We write the
 | 
				
			||||||
	 * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original
 | 
							 * constant KPROBE_ON_FTRACE_NOP into the remaining four
 | 
				
			||||||
	 * instruction so that the kprobes handler can execute a nop, if it
 | 
							 * bytes of the original instruction so that the kprobes
 | 
				
			||||||
	 * reaches this breakpoint.
 | 
							 * handler can execute a nop, if it reaches this breakpoint.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
	if (op == BREAKPOINT_INSTRUCTION) {
 | 
							new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
 | 
				
			||||||
		size -= 2;
 | 
							orig.disp = KPROBE_ON_FTRACE_CALL;
 | 
				
			||||||
		from += 2;
 | 
							new.disp = KPROBE_ON_FTRACE_NOP;
 | 
				
			||||||
		to += 2;
 | 
						} else {
 | 
				
			||||||
		insn.disp = KPROBE_ON_FTRACE_NOP;
 | 
							/* 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 -EPERM;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 | 
					int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ftrace_insn insn;
 | 
						struct ftrace_insn orig, new, old;
 | 
				
			||||||
	unsigned short op;
 | 
					 | 
				
			||||||
	void *from, *to;
 | 
					 | 
				
			||||||
	size_t size;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ftrace_generate_call_insn(&insn, rec->ip);
 | 
						if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
 | 
				
			||||||
	size = sizeof(insn);
 | 
					 | 
				
			||||||
	from = &insn;
 | 
					 | 
				
			||||||
	to = (void *) rec->ip;
 | 
					 | 
				
			||||||
	if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op)))
 | 
					 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
						if (old.opc == BREAKPOINT_INSTRUCTION) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
	 * If we find a breakpoint instruction, a kprobe has been placed
 | 
							 * If we find a breakpoint instruction, a kprobe has been
 | 
				
			||||||
	 * at the beginning of the function. We write the constant
 | 
							 * placed at the beginning of the function. We write the
 | 
				
			||||||
	 * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original
 | 
							 * constant KPROBE_ON_FTRACE_CALL into the remaining four
 | 
				
			||||||
	 * instruction so that the kprobes handler can execute a brasl if it
 | 
							 * bytes of the original instruction so that the kprobes
 | 
				
			||||||
	 * reaches this breakpoint.
 | 
							 * handler can execute a brasl if it reaches this breakpoint.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
	if (op == BREAKPOINT_INSTRUCTION) {
 | 
							new.opc = orig.opc = BREAKPOINT_INSTRUCTION;
 | 
				
			||||||
		size -= 2;
 | 
							orig.disp = KPROBE_ON_FTRACE_NOP;
 | 
				
			||||||
		from += 2;
 | 
							new.disp = KPROBE_ON_FTRACE_CALL;
 | 
				
			||||||
		to += 2;
 | 
						} else {
 | 
				
			||||||
		insn.disp = KPROBE_ON_FTRACE_CALL;
 | 
							/* 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 -EPERM;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -436,7 +436,9 @@ ENTRY(startup_kdump)
 | 
				
			||||||
# followed by the facility words.
 | 
					# followed by the facility words.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_64BIT)
 | 
					#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
 | 
						.long 3, 0xc100eff2, 0xf46ce800, 0x00400000
 | 
				
			||||||
#elif defined(CONFIG_MARCH_Z196)
 | 
					#elif defined(CONFIG_MARCH_Z196)
 | 
				
			||||||
	.long 2, 0xc100eff2, 0xf46c0000
 | 
						.long 2, 0xc100eff2, 0xf46c0000
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2074,7 +2074,8 @@ static void do_reset_calls(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
u32 dump_prefix_page;
 | 
					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;
 | 
						struct _lowcore *lc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data)
 | 
				
			||||||
	/* Store status at absolute zero */
 | 
						/* Store status at absolute zero */
 | 
				
			||||||
	store_status();
 | 
						store_status();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Call function before reset */
 | 
				
			||||||
 | 
						if (fn_pre)
 | 
				
			||||||
 | 
							fn_pre();
 | 
				
			||||||
	do_reset_calls();
 | 
						do_reset_calls();
 | 
				
			||||||
	if (func)
 | 
						/* Call function after reset */
 | 
				
			||||||
		func(data);
 | 
						if (fn_post)
 | 
				
			||||||
 | 
							fn_post(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,31 +22,66 @@ struct insn_args {
 | 
				
			||||||
	enum jump_label_type type;
 | 
						enum jump_label_type type;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __jump_label_transform(struct jump_entry *entry,
 | 
					static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
 | 
				
			||||||
				   enum jump_label_type type)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct insn insn;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (type == JUMP_LABEL_ENABLE) {
 | 
					 | 
				
			||||||
		/* brcl 15,offset */
 | 
					 | 
				
			||||||
		insn.opcode = 0xc0f4;
 | 
					 | 
				
			||||||
		insn.offset = (entry->target - entry->code) >> 1;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
	/* brcl 0,0 */
 | 
						/* brcl 0,0 */
 | 
				
			||||||
		insn.opcode = 0xc004;
 | 
						insn->opcode = 0xc004;
 | 
				
			||||||
		insn.offset = 0;
 | 
						insn->offset = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE);
 | 
					static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
 | 
				
			||||||
	WARN_ON_ONCE(rc < 0);
 | 
					{
 | 
				
			||||||
 | 
						/* 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,
 | 
				
			||||||
 | 
									   int init)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct insn old, new;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (type == JUMP_LABEL_ENABLE) {
 | 
				
			||||||
 | 
							jump_label_make_nop(entry, &old);
 | 
				
			||||||
 | 
							jump_label_make_branch(entry, &new);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							jump_label_make_branch(entry, &old);
 | 
				
			||||||
 | 
							jump_label_make_nop(entry, &new);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						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)
 | 
					static int __sm_arch_jump_label_transform(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct insn_args *args = data;
 | 
						struct insn_args *args = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__jump_label_transform(args->entry, args->type);
 | 
						__jump_label_transform(args->entry, args->type, 0);
 | 
				
			||||||
	return 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,
 | 
					void arch_jump_label_transform_static(struct jump_entry *entry,
 | 
				
			||||||
				      enum jump_label_type type)
 | 
									      enum jump_label_type type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__jump_label_transform(entry, type);
 | 
						__jump_label_transform(entry, type, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * If kprobes patches the instruction that is morphed by
 | 
							 * If kprobes patches the instruction that is morphed by
 | 
				
			||||||
		 * ftrace make sure that kprobes always sees the branch
 | 
							 * 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);
 | 
							ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
 | 
				
			||||||
		p->ainsn.is_ftrace_insn = 1;
 | 
							p->ainsn.is_ftrace_insn = 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
arch_initcall(machine_kdump_pm_init);
 | 
					arch_initcall(machine_kdump_pm_init);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Start kdump: We expect here that a store status has been done on our CPU
 | 
					 * Start kdump: We expect here that a store status has been done on our CPU
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void __do_machine_kdump(void *image)
 | 
					static void __do_machine_kdump(void *image)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_CRASH_DUMP
 | 
					 | 
				
			||||||
	int (*start_kdump)(int) = (void *)((struct kimage *) image)->start;
 | 
						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);
 | 
						__load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
 | 
				
			||||||
	start_kdump(1);
 | 
						start_kdump(1);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Check if kdump checksums are valid: We call purgatory with parameter "0"
 | 
					 * 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)
 | 
					static void __machine_kexec(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kimage *image = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__arch_local_irq_stosm(0x04); /* enable DAT */
 | 
						__arch_local_irq_stosm(0x04); /* enable DAT */
 | 
				
			||||||
	pfault_fini();
 | 
						pfault_fini();
 | 
				
			||||||
	tracing_off();
 | 
						tracing_off();
 | 
				
			||||||
	debug_locks_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();
 | 
							lgr_info_log();
 | 
				
			||||||
		s390_reset_system(__do_machine_kdump, data);
 | 
							s390_reset_system(setup_regs, __do_machine_kdump, data);
 | 
				
			||||||
	} else {
 | 
						} else
 | 
				
			||||||
		s390_reset_system(__do_machine_kexec, data);
 | 
					#endif
 | 
				
			||||||
	}
 | 
							s390_reset_system(NULL, __do_machine_kexec, data);
 | 
				
			||||||
	disabled_wait((unsigned long) __builtin_return_address(0));
 | 
						disabled_wait((unsigned long) __builtin_return_address(0));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,9 @@ ENTRY(ftrace_caller)
 | 
				
			||||||
	.globl	ftrace_regs_caller
 | 
						.globl	ftrace_regs_caller
 | 
				
			||||||
	.set	ftrace_regs_caller,ftrace_caller
 | 
						.set	ftrace_regs_caller,ftrace_caller
 | 
				
			||||||
	lgr	%r1,%r15
 | 
						lgr	%r1,%r15
 | 
				
			||||||
 | 
					#ifndef CC_USING_HOTPATCH
 | 
				
			||||||
	aghi	%r0,MCOUNT_RETURN_FIXUP
 | 
						aghi	%r0,MCOUNT_RETURN_FIXUP
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	aghi	%r15,-STACK_FRAME_SIZE
 | 
						aghi	%r15,-STACK_FRAME_SIZE
 | 
				
			||||||
	stg	%r1,__SF_BACKCHAIN(%r15)
 | 
						stg	%r1,__SF_BACKCHAIN(%r15)
 | 
				
			||||||
	stg	%r1,(STACK_PTREGS_GPRS+15*8)(%r15)
 | 
						stg	%r1,(STACK_PTREGS_GPRS+15*8)(%r15)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
					int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 | 
				
			||||||
		unsigned long arg, struct task_struct *p)
 | 
							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());
 | 
						ret = PAGE_ALIGN(mm->brk + brk_rnd());
 | 
				
			||||||
	return (ret > mm->brk) ? ret : mm->brk;
 | 
						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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,16 +8,24 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
#include <linux/smp.h>
 | 
					 | 
				
			||||||
#include <linux/seq_file.h>
 | 
					#include <linux/seq_file.h>
 | 
				
			||||||
#include <linux/delay.h>
 | 
					#include <linux/delay.h>
 | 
				
			||||||
#include <linux/cpu.h>
 | 
					#include <linux/cpu.h>
 | 
				
			||||||
#include <asm/elf.h>
 | 
					#include <asm/elf.h>
 | 
				
			||||||
#include <asm/lowcore.h>
 | 
					#include <asm/lowcore.h>
 | 
				
			||||||
#include <asm/param.h>
 | 
					#include <asm/param.h>
 | 
				
			||||||
 | 
					#include <asm/smp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEFINE_PER_CPU(struct cpuid, cpu_id);
 | 
					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.
 | 
					 * cpu_init - initializes state that is per-CPU.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,7 +294,8 @@ ENTRY(_sclp_print_early)
 | 
				
			||||||
#ifdef CONFIG_64BIT
 | 
					#ifdef CONFIG_64BIT
 | 
				
			||||||
	tm	LC_AR_MODE_ID,1
 | 
						tm	LC_AR_MODE_ID,1
 | 
				
			||||||
	jno	.Lesa3
 | 
						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
 | 
						ahi	%r15,80
 | 
				
			||||||
.Lesa3:
 | 
					.Lesa3:
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -810,6 +810,9 @@ static void __init setup_hwcaps(void)
 | 
				
			||||||
	case 0x2828:
 | 
						case 0x2828:
 | 
				
			||||||
		strcpy(elf_platform, "zEC12");
 | 
							strcpy(elf_platform, "zEC12");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case 0x2964:
 | 
				
			||||||
 | 
							strcpy(elf_platform, "z13");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,9 +71,30 @@ struct pcpu {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u8 boot_cpu_type;
 | 
					static u8 boot_cpu_type;
 | 
				
			||||||
static u16 boot_cpu_address;
 | 
					 | 
				
			||||||
static struct pcpu pcpu_devices[NR_CPUS];
 | 
					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
 | 
					 * 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.
 | 
					 * 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.
 | 
					 * 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;
 | 
						int cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,6 +319,32 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
 | 
				
			||||||
	for (;;) ;
 | 
						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.
 | 
					 * Call function on an online CPU.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -512,22 +559,17 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CRASH_DUMP
 | 
					#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;
 | 
						void *lc = pcpu_devices[0].lowcore;
 | 
				
			||||||
	struct save_area_ext *sa_ext;
 | 
						struct save_area_ext *sa_ext;
 | 
				
			||||||
	unsigned long vx_sa;
 | 
						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);
 | 
						sa_ext = dump_save_area_create(cpu);
 | 
				
			||||||
	if (!sa_ext)
 | 
						if (!sa_ext)
 | 
				
			||||||
		panic("could not allocate memory for save area\n");
 | 
							panic("could not allocate memory for save area\n");
 | 
				
			||||||
	if (address == boot_cpu_address) {
 | 
						if (is_boot_cpu) {
 | 
				
			||||||
		/* Copy the registers of the boot cpu. */
 | 
							/* Copy the registers of the boot CPU. */
 | 
				
			||||||
		copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
 | 
							copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
 | 
				
			||||||
				 SAVE_AREA_BASE - PAGE_SIZE, 0);
 | 
									 SAVE_AREA_BASE - PAGE_SIZE, 0);
 | 
				
			||||||
		if (MACHINE_HAS_VX)
 | 
							if (MACHINE_HAS_VX)
 | 
				
			||||||
| 
						 | 
					@ -548,6 +590,64 @@ static void __init smp_get_save_area(int cpu, u16 address)
 | 
				
			||||||
	free_page(vx_sa);
 | 
						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)
 | 
					int smp_store_status(int cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long vx_sa;
 | 
						unsigned long vx_sa;
 | 
				
			||||||
| 
						 | 
					@ -565,10 +665,6 @@ int smp_store_status(int cpu)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* CONFIG_CRASH_DUMP */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void smp_get_save_area(int cpu, u16 address) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* CONFIG_CRASH_DUMP */
 | 
					#endif /* CONFIG_CRASH_DUMP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void smp_cpu_set_polarization(int cpu, int val)
 | 
					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);
 | 
						info = kzalloc(sizeof(*info), GFP_KERNEL);
 | 
				
			||||||
	if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
 | 
						if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
 | 
				
			||||||
		use_sigp_detection = 1;
 | 
							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) ==
 | 
								if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
 | 
				
			||||||
			    SIGP_CC_NOT_OPERATIONAL)
 | 
								    SIGP_CC_NOT_OPERATIONAL)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			info->cpu[info->configured].address = address;
 | 
								info->cpu[info->configured].core_id =
 | 
				
			||||||
 | 
									address >> smp_cpu_mt_shift;
 | 
				
			||||||
			info->configured++;
 | 
								info->configured++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		info->combined = 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;
 | 
						struct pcpu *pcpu;
 | 
				
			||||||
	cpumask_t avail;
 | 
						cpumask_t avail;
 | 
				
			||||||
	int cpu, nr, i;
 | 
						int cpu, nr, i, j;
 | 
				
			||||||
 | 
						u16 address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nr = 0;
 | 
						nr = 0;
 | 
				
			||||||
	cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
 | 
						cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
 | 
				
			||||||
| 
						 | 
					@ -616,11 +715,14 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)
 | 
				
			||||||
	for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
 | 
						for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) {
 | 
				
			||||||
		if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
 | 
							if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (pcpu_find_address(cpu_present_mask, info->cpu[i].address))
 | 
							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;
 | 
									continue;
 | 
				
			||||||
			pcpu = pcpu_devices + cpu;
 | 
								pcpu = pcpu_devices + cpu;
 | 
				
			||||||
		pcpu->address = info->cpu[i].address;
 | 
								pcpu->address = address + j;
 | 
				
			||||||
		pcpu->state = (i >= info->configured) ?
 | 
								pcpu->state =
 | 
				
			||||||
 | 
									(cpu >= info->configured*(smp_cpu_mtid + 1)) ?
 | 
				
			||||||
				CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
 | 
									CPU_STATE_STANDBY : CPU_STATE_CONFIGURED;
 | 
				
			||||||
			smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 | 
								smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 | 
				
			||||||
			set_cpu_present(cpu, true);
 | 
								set_cpu_present(cpu, true);
 | 
				
			||||||
| 
						 | 
					@ -629,38 +731,60 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add)
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				nr++;
 | 
									nr++;
 | 
				
			||||||
			cpu = cpumask_next(cpu, &avail);
 | 
								cpu = cpumask_next(cpu, &avail);
 | 
				
			||||||
 | 
								if (cpu >= nr_cpu_ids)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nr;
 | 
						return nr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init smp_detect_cpus(void)
 | 
					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;
 | 
						struct sclp_cpu_info *info;
 | 
				
			||||||
 | 
						u16 address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get CPU information */
 | 
				
			||||||
	info = smp_get_cpu_info();
 | 
						info = smp_get_cpu_info();
 | 
				
			||||||
	if (!info)
 | 
						if (!info)
 | 
				
			||||||
		panic("smp_detect_cpus failed to allocate memory\n");
 | 
							panic("smp_detect_cpus failed to allocate memory\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find boot CPU type */
 | 
				
			||||||
	if (info->has_cpu_type) {
 | 
						if (info->has_cpu_type) {
 | 
				
			||||||
		for (cpu = 0; cpu < info->combined; cpu++) {
 | 
							address = stap();
 | 
				
			||||||
			if (info->cpu[cpu].address != boot_cpu_address)
 | 
							for (cpu = 0; cpu < info->combined; cpu++)
 | 
				
			||||||
				continue;
 | 
								if (info->cpu[cpu].core_id == address) {
 | 
				
			||||||
				/* The boot cpu dictates the cpu type. */
 | 
									/* The boot cpu dictates the cpu type. */
 | 
				
			||||||
				boot_cpu_type = info->cpu[cpu].type;
 | 
									boot_cpu_type = info->cpu[cpu].type;
 | 
				
			||||||
				break;
 | 
									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;
 | 
						c_cpus = s_cpus = 0;
 | 
				
			||||||
	for (cpu = 0; cpu < info->combined; cpu++) {
 | 
						for (cpu = 0; cpu < info->combined; cpu++) {
 | 
				
			||||||
		if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type)
 | 
							if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (cpu < info->configured) {
 | 
							if (cpu < info->configured)
 | 
				
			||||||
			smp_get_save_area(c_cpus, info->cpu[cpu].address);
 | 
								c_cpus += smp_cpu_mtid + 1;
 | 
				
			||||||
			c_cpus++;
 | 
							else
 | 
				
			||||||
		} else
 | 
								s_cpus += smp_cpu_mtid + 1;
 | 
				
			||||||
			s_cpus++;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
 | 
						pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add CPUs present at boot */
 | 
				
			||||||
	get_online_cpus();
 | 
						get_online_cpus();
 | 
				
			||||||
	__smp_rescan_cpus(info, 0);
 | 
						__smp_rescan_cpus(info, 0);
 | 
				
			||||||
	put_online_cpus();
 | 
						put_online_cpus();
 | 
				
			||||||
| 
						 | 
					@ -696,12 +820,23 @@ static void smp_start_secondary(void *cpuvoid)
 | 
				
			||||||
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 | 
					int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pcpu *pcpu;
 | 
						struct pcpu *pcpu;
 | 
				
			||||||
	int rc;
 | 
						int base, i, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pcpu = pcpu_devices + cpu;
 | 
						pcpu = pcpu_devices + cpu;
 | 
				
			||||||
	if (pcpu->state != CPU_STATE_CONFIGURED)
 | 
						if (pcpu->state != CPU_STATE_CONFIGURED)
 | 
				
			||||||
		return -EIO;
 | 
							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)
 | 
						    SIGP_CC_ORDER_CODE_ACCEPTED)
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -774,7 +909,8 @@ void __init smp_fill_possible_mask(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int possible, sclp, cpu;
 | 
						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 = setup_possible_cpus ?: nr_cpu_ids;
 | 
				
			||||||
	possible = min(possible, sclp);
 | 
						possible = min(possible, sclp);
 | 
				
			||||||
	for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
 | 
						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;
 | 
						struct pcpu *pcpu = pcpu_devices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	boot_cpu_address = stap();
 | 
					 | 
				
			||||||
	pcpu->state = CPU_STATE_CONFIGURED;
 | 
						pcpu->state = CPU_STATE_CONFIGURED;
 | 
				
			||||||
	pcpu->address = boot_cpu_address;
 | 
						pcpu->address = stap();
 | 
				
			||||||
	pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
 | 
						pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
 | 
				
			||||||
	pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
 | 
						pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
 | 
				
			||||||
		+ STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
 | 
							+ 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)
 | 
									   const char *buf, size_t count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pcpu *pcpu;
 | 
						struct pcpu *pcpu;
 | 
				
			||||||
	int cpu, val, rc;
 | 
						int cpu, val, rc, i;
 | 
				
			||||||
	char delim;
 | 
						char delim;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sscanf(buf, "%d %c", &val, &delim) != 1)
 | 
						if (sscanf(buf, "%d %c", &val, &delim) != 1)
 | 
				
			||||||
| 
						 | 
					@ -860,7 +995,11 @@ static ssize_t cpu_configure_store(struct device *dev,
 | 
				
			||||||
	rc = -EBUSY;
 | 
						rc = -EBUSY;
 | 
				
			||||||
	/* disallow configuration changes of online cpus and cpu 0 */
 | 
						/* disallow configuration changes of online cpus and cpu 0 */
 | 
				
			||||||
	cpu = dev->id;
 | 
						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;
 | 
								goto out;
 | 
				
			||||||
	pcpu = pcpu_devices + cpu;
 | 
						pcpu = pcpu_devices + cpu;
 | 
				
			||||||
	rc = 0;
 | 
						rc = 0;
 | 
				
			||||||
| 
						 | 
					@ -868,21 +1007,31 @@ static ssize_t cpu_configure_store(struct device *dev,
 | 
				
			||||||
	case 0:
 | 
						case 0:
 | 
				
			||||||
		if (pcpu->state != CPU_STATE_CONFIGURED)
 | 
							if (pcpu->state != CPU_STATE_CONFIGURED)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		rc = sclp_cpu_deconfigure(pcpu->address);
 | 
							rc = sclp_cpu_deconfigure(pcpu->address >> smp_cpu_mt_shift);
 | 
				
			||||||
		if (rc)
 | 
							if (rc)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		pcpu->state = CPU_STATE_STANDBY;
 | 
							for (i = 0; i <= smp_cpu_mtid; i++) {
 | 
				
			||||||
		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 | 
								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();
 | 
							topology_expect_change();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 1:
 | 
						case 1:
 | 
				
			||||||
		if (pcpu->state != CPU_STATE_STANDBY)
 | 
							if (pcpu->state != CPU_STATE_STANDBY)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		rc = sclp_cpu_configure(pcpu->address);
 | 
							rc = sclp_cpu_configure(pcpu->address >> smp_cpu_mt_shift);
 | 
				
			||||||
		if (rc)
 | 
							if (rc)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		pcpu->state = CPU_STATE_CONFIGURED;
 | 
							for (i = 0; i <= smp_cpu_mtid; i++) {
 | 
				
			||||||
		smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN);
 | 
								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();
 | 
							topology_expect_change();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 Reserved:   %d\n", info->cpus_reserved);
 | 
				
			||||||
	seq_printf(m, "LPAR CPUs Dedicated:  %d\n", info->cpus_dedicated);
 | 
						seq_printf(m, "LPAR CPUs Dedicated:  %d\n", info->cpus_dedicated);
 | 
				
			||||||
	seq_printf(m, "LPAR CPUs Shared:     %d\n", info->cpus_shared);
 | 
						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)
 | 
					static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,32 +59,50 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 | 
				
			||||||
	return mask;
 | 
						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 *book,
 | 
				
			||||||
					  struct mask_info *socket,
 | 
										  struct mask_info *socket,
 | 
				
			||||||
					  int one_socket_per_cpu)
 | 
										  int one_socket_per_cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int cpu;
 | 
						unsigned int core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) {
 | 
						for_each_set_bit(core, &tl_core->mask[0], TOPOLOGY_CORE_BITS) {
 | 
				
			||||||
		unsigned int rcpu;
 | 
							unsigned int rcore;
 | 
				
			||||||
		int lcpu;
 | 
							int lcpu, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
 | 
							rcore = TOPOLOGY_CORE_BITS - 1 - core + tl_core->origin;
 | 
				
			||||||
		lcpu = smp_find_processor_id(rcpu);
 | 
							lcpu = smp_find_processor_id(rcore << smp_cpu_mt_shift);
 | 
				
			||||||
		if (lcpu < 0)
 | 
							if (lcpu < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		cpumask_set_cpu(lcpu, &book->mask);
 | 
							for (i = 0; i <= smp_cpu_mtid; i++) {
 | 
				
			||||||
		cpu_topology[lcpu].book_id = book->id;
 | 
								cpu_topology[lcpu + i].book_id = book->id;
 | 
				
			||||||
		cpumask_set_cpu(lcpu, &socket->mask);
 | 
								cpu_topology[lcpu + i].core_id = rcore;
 | 
				
			||||||
		cpu_topology[lcpu].core_id = rcpu;
 | 
								cpu_topology[lcpu + i].thread_id = lcpu + i;
 | 
				
			||||||
		if (one_socket_per_cpu) {
 | 
								cpumask_set_cpu(lcpu + i, &book->mask);
 | 
				
			||||||
			cpu_topology[lcpu].socket_id = rcpu;
 | 
								cpumask_set_cpu(lcpu + i, &socket->mask);
 | 
				
			||||||
			socket = socket->next;
 | 
								if (one_socket_per_cpu)
 | 
				
			||||||
		} else {
 | 
									cpu_topology[lcpu + i].socket_id = rcore;
 | 
				
			||||||
			cpu_topology[lcpu].socket_id = socket->id;
 | 
								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;
 | 
						return socket;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -108,7 +126,7 @@ static void clear_masks(void)
 | 
				
			||||||
static union topology_entry *next_tle(union topology_entry *tle)
 | 
					static union topology_entry *next_tle(union topology_entry *tle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!tle->nl)
 | 
						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);
 | 
						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);
 | 
						spin_lock_irqsave(&topology_lock, flags);
 | 
				
			||||||
	for_each_possible_cpu(cpu) {
 | 
						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].core_mask = cpu_group_map(&socket_info, cpu);
 | 
				
			||||||
		cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu);
 | 
							cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu);
 | 
				
			||||||
		if (!MACHINE_HAS_TOPOLOGY) {
 | 
							if (!MACHINE_HAS_TOPOLOGY) {
 | 
				
			||||||
 | 
								cpu_topology[cpu].thread_id = cpu;
 | 
				
			||||||
			cpu_topology[cpu].core_id = cpu;
 | 
								cpu_topology[cpu].core_id = cpu;
 | 
				
			||||||
			cpu_topology[cpu].socket_id = cpu;
 | 
								cpu_topology[cpu].socket_id = cpu;
 | 
				
			||||||
			cpu_topology[cpu].book_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);
 | 
						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)
 | 
					const struct cpumask *cpu_coregroup_mask(int cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return &cpu_topology[cpu].core_mask;
 | 
						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[] = {
 | 
					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_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
 | 
				
			||||||
	{ cpu_book_mask, SD_INIT_NAME(BOOK) },
 | 
						{ cpu_book_mask, SD_INIT_NAME(BOOK) },
 | 
				
			||||||
	{ cpu_cpu_mask, SD_INIT_NAME(DIE) },
 | 
						{ cpu_cpu_mask, SD_INIT_NAME(DIE) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,8 @@
 | 
				
			||||||
#include <asm/cputime.h>
 | 
					#include <asm/cputime.h>
 | 
				
			||||||
#include <asm/vtimer.h>
 | 
					#include <asm/vtimer.h>
 | 
				
			||||||
#include <asm/vtime.h>
 | 
					#include <asm/vtime.h>
 | 
				
			||||||
 | 
					#include <asm/cpu_mf.h>
 | 
				
			||||||
 | 
					#include <asm/smp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virt_timer_expire(void);
 | 
					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_current;
 | 
				
			||||||
static atomic64_t virt_timer_elapsed;
 | 
					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)
 | 
					static inline u64 get_vtimer(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u64 timer;
 | 
						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);
 | 
						struct thread_info *ti = task_thread_info(tsk);
 | 
				
			||||||
	u64 timer, clock, user, system, steal;
 | 
						u64 timer, clock, user, system, steal;
 | 
				
			||||||
 | 
						u64 user_scaled, system_scaled;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	timer = S390_lowcore.last_update_timer;
 | 
						timer = S390_lowcore.last_update_timer;
 | 
				
			||||||
	clock = S390_lowcore.last_update_clock;
 | 
						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.system_timer += timer - S390_lowcore.last_update_timer;
 | 
				
			||||||
	S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock;
 | 
						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;
 | 
						user = S390_lowcore.user_timer - ti->user_timer;
 | 
				
			||||||
	S390_lowcore.steal_timer -= user;
 | 
						S390_lowcore.steal_timer -= user;
 | 
				
			||||||
	ti->user_timer = S390_lowcore.user_timer;
 | 
						ti->user_timer = S390_lowcore.user_timer;
 | 
				
			||||||
	account_user_time(tsk, user, user);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	system = S390_lowcore.system_timer - ti->system_timer;
 | 
						system = S390_lowcore.system_timer - ti->system_timer;
 | 
				
			||||||
	S390_lowcore.steal_timer -= system;
 | 
						S390_lowcore.steal_timer -= system;
 | 
				
			||||||
	ti->system_timer = S390_lowcore.system_timer;
 | 
						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;
 | 
						steal = S390_lowcore.steal_timer;
 | 
				
			||||||
	if ((s64) steal > 0) {
 | 
						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)
 | 
					void vtime_account_irq_enter(struct task_struct *tsk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread_info *ti = task_thread_info(tsk);
 | 
						struct thread_info *ti = task_thread_info(tsk);
 | 
				
			||||||
	u64 timer, system;
 | 
						u64 timer, system, system_scaled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	timer = S390_lowcore.last_update_timer;
 | 
						timer = S390_lowcore.last_update_timer;
 | 
				
			||||||
	S390_lowcore.last_update_timer = get_vtimer();
 | 
						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;
 | 
						system = S390_lowcore.system_timer - ti->system_timer;
 | 
				
			||||||
	S390_lowcore.steal_timer -= system;
 | 
						S390_lowcore.steal_timer -= system;
 | 
				
			||||||
	ti->system_timer = S390_lowcore.system_timer;
 | 
						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);
 | 
						virt_timer_forward(system);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,15 @@
 | 
				
			||||||
#include <linux/smp.h>
 | 
					#include <linux/smp.h>
 | 
				
			||||||
#include <asm/io.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
 | 
					 * spin_retry= parameter
 | 
				
			||||||
| 
						 | 
					@ -24,6 +32,11 @@ static int __init spin_retry_setup(char *str)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
__setup("spin_retry=", spin_retry_setup);
 | 
					__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)
 | 
					void arch_spin_lock_wait(arch_spinlock_t *lp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int cpu = SPINLOCK_LOCKVAL;
 | 
						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. */
 | 
							/* Loop for a while on the lock value. */
 | 
				
			||||||
		count = spin_retry;
 | 
							count = spin_retry;
 | 
				
			||||||
		do {
 | 
							do {
 | 
				
			||||||
 | 
								if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
									_raw_compare_and_delay(&lp->lock, owner);
 | 
				
			||||||
			owner = ACCESS_ONCE(lp->lock);
 | 
								owner = ACCESS_ONCE(lp->lock);
 | 
				
			||||||
		} while (owner && count-- > 0);
 | 
							} while (owner && count-- > 0);
 | 
				
			||||||
		if (!owner)
 | 
							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. */
 | 
							/* Loop for a while on the lock value. */
 | 
				
			||||||
		count = spin_retry;
 | 
							count = spin_retry;
 | 
				
			||||||
		do {
 | 
							do {
 | 
				
			||||||
 | 
								if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
									_raw_compare_and_delay(&lp->lock, owner);
 | 
				
			||||||
			owner = ACCESS_ONCE(lp->lock);
 | 
								owner = ACCESS_ONCE(lp->lock);
 | 
				
			||||||
		} while (owner && count-- > 0);
 | 
							} while (owner && count-- > 0);
 | 
				
			||||||
		if (!owner)
 | 
							if (!owner)
 | 
				
			||||||
| 
						 | 
					@ -100,11 +117,19 @@ EXPORT_SYMBOL(arch_spin_lock_wait_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int arch_spin_trylock_retry(arch_spinlock_t *lp)
 | 
					int arch_spin_trylock_retry(arch_spinlock_t *lp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						unsigned int cpu = SPINLOCK_LOCKVAL;
 | 
				
			||||||
 | 
						unsigned int owner;
 | 
				
			||||||
	int count;
 | 
						int count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (count = spin_retry; count > 0; count--)
 | 
						for (count = spin_retry; count > 0; count--) {
 | 
				
			||||||
		if (arch_spin_trylock_once(lp))
 | 
							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;
 | 
									return 1;
 | 
				
			||||||
 | 
							} else if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
								_raw_compare_and_delay(&lp->lock, owner);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(arch_spin_trylock_retry);
 | 
					EXPORT_SYMBOL(arch_spin_trylock_retry);
 | 
				
			||||||
| 
						 | 
					@ -126,8 +151,11 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		old = ACCESS_ONCE(rw->lock);
 | 
							old = ACCESS_ONCE(rw->lock);
 | 
				
			||||||
		owner = ACCESS_ONCE(rw->owner);
 | 
							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;
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (_raw_compare_and_swap(&rw->lock, old, old + 1))
 | 
							if (_raw_compare_and_swap(&rw->lock, old, old + 1))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -141,8 +169,11 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (count-- > 0) {
 | 
						while (count-- > 0) {
 | 
				
			||||||
		old = ACCESS_ONCE(rw->lock);
 | 
							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;
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (_raw_compare_and_swap(&rw->lock, old, old + 1))
 | 
							if (_raw_compare_and_swap(&rw->lock, old, old + 1))
 | 
				
			||||||
			return 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)
 | 
							if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
								_raw_compare_and_delay(&rw->lock, old);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(_raw_write_lock_wait);
 | 
					EXPORT_SYMBOL(_raw_write_lock_wait);
 | 
				
			||||||
| 
						 | 
					@ -201,6 +234,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw)
 | 
				
			||||||
			smp_rmb();
 | 
								smp_rmb();
 | 
				
			||||||
		if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
 | 
							if ((old & 0x7fffffff) == 0 && (int) prev >= 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
								_raw_compare_and_delay(&rw->lock, old);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(_raw_write_lock_wait);
 | 
					EXPORT_SYMBOL(_raw_write_lock_wait);
 | 
				
			||||||
| 
						 | 
					@ -214,8 +249,11 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (count-- > 0) {
 | 
						while (count-- > 0) {
 | 
				
			||||||
		old = ACCESS_ONCE(rw->lock);
 | 
							old = ACCESS_ONCE(rw->lock);
 | 
				
			||||||
		if (old)
 | 
							if (old) {
 | 
				
			||||||
 | 
								if (MACHINE_HAS_CAD)
 | 
				
			||||||
 | 
									_raw_compare_and_delay(&rw->lock, old);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
 | 
							if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address)
 | 
				
			||||||
		table = table + ((address >> 20) & 0x7ff);
 | 
							table = table + ((address >> 20) & 0x7ff);
 | 
				
			||||||
		if (bad_address(table))
 | 
							if (bad_address(table))
 | 
				
			||||||
			goto bad;
 | 
								goto bad;
 | 
				
			||||||
		pr_cont(KERN_CONT "S:%016lx ", *table);
 | 
							pr_cont("S:%016lx ", *table);
 | 
				
			||||||
		if (*table & (_SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_LARGE))
 | 
							if (*table & (_SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_LARGE))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
 | 
							table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,13 +71,16 @@ static void __init setup_zero_pages(void)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 0x2827:	/* zEC12 */
 | 
						case 0x2827:	/* zEC12 */
 | 
				
			||||||
	case 0x2828:	/* zEC12 */
 | 
						case 0x2828:	/* zEC12 */
 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		order = 5;
 | 
							order = 5;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case 0x2964:	/* z13 */
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							order = 7;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Limit number of empty zero pages for small memory sizes */
 | 
						/* Limit number of empty zero pages for small memory sizes */
 | 
				
			||||||
	if (order > 2 && totalram_pages <= 16384)
 | 
						while (order > 2 && (totalram_pages >> 10) < (1UL << order))
 | 
				
			||||||
		order = 2;
 | 
							order--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
 | 
						empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
 | 
				
			||||||
	if (!empty_zero_page)
 | 
						if (!empty_zero_page)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,8 +28,12 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/random.h>
 | 
					#include <linux/random.h>
 | 
				
			||||||
#include <linux/compat.h>
 | 
					#include <linux/compat.h>
 | 
				
			||||||
 | 
					#include <linux/security.h>
 | 
				
			||||||
#include <asm/pgalloc.h>
 | 
					#include <asm/pgalloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned long mmap_rnd_mask;
 | 
				
			||||||
 | 
					unsigned long mmap_align_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long stack_maxrandom_size(void)
 | 
					static unsigned long stack_maxrandom_size(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!(current->flags & PF_RANDOMIZE))
 | 
						if (!(current->flags & PF_RANDOMIZE))
 | 
				
			||||||
| 
						 | 
					@ -60,8 +64,10 @@ static unsigned long mmap_rnd(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!(current->flags & PF_RANDOMIZE))
 | 
						if (!(current->flags & PF_RANDOMIZE))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	/* 8MB randomization for mmap_base */
 | 
						if (is_32bit_task())
 | 
				
			||||||
	return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
 | 
							return (get_random_int() & 0x7ff) << PAGE_SHIFT;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return (get_random_int() & mmap_rnd_mask) << PAGE_SHIFT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long mmap_base_legacy(void)
 | 
					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;
 | 
						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
 | 
					#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
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -527,7 +527,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
 | 
				
			||||||
		table += (gaddr >> 53) & 0x7ff;
 | 
							table += (gaddr >> 53) & 0x7ff;
 | 
				
			||||||
		if ((*table & _REGION_ENTRY_INVALID) &&
 | 
							if ((*table & _REGION_ENTRY_INVALID) &&
 | 
				
			||||||
		    gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY,
 | 
							    gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY,
 | 
				
			||||||
				     gaddr & 0xffe0000000000000))
 | 
									     gaddr & 0xffe0000000000000UL))
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 | 
							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;
 | 
							table += (gaddr >> 42) & 0x7ff;
 | 
				
			||||||
		if ((*table & _REGION_ENTRY_INVALID) &&
 | 
							if ((*table & _REGION_ENTRY_INVALID) &&
 | 
				
			||||||
		    gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY,
 | 
							    gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY,
 | 
				
			||||||
				     gaddr & 0xfffffc0000000000))
 | 
									     gaddr & 0xfffffc0000000000UL))
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 | 
							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;
 | 
							table += (gaddr >> 31) & 0x7ff;
 | 
				
			||||||
		if ((*table & _REGION_ENTRY_INVALID) &&
 | 
							if ((*table & _REGION_ENTRY_INVALID) &&
 | 
				
			||||||
		    gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY,
 | 
							    gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY,
 | 
				
			||||||
				     gaddr & 0xffffffff80000000))
 | 
									     gaddr & 0xffffffff80000000UL))
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 | 
							table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,7 +55,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
 | 
				
			||||||
	ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
 | 
						ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out;
 | 
							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;
 | 
						ret = -EFAULT;
 | 
				
			||||||
	if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
 | 
						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);
 | 
						ret = get_pfn(mmio_addr, VM_READ, &pfn);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out;
 | 
							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;
 | 
						ret = -EFAULT;
 | 
				
			||||||
	if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
 | 
						if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -674,8 +674,9 @@ EXPORT_SYMBOL(dasd_enable_device);
 | 
				
			||||||
unsigned int dasd_global_profile_level = DASD_PROFILE_OFF;
 | 
					unsigned int dasd_global_profile_level = DASD_PROFILE_OFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DASD_PROFILE
 | 
					#ifdef CONFIG_DASD_PROFILE
 | 
				
			||||||
struct dasd_profile_info dasd_global_profile_data;
 | 
					struct dasd_profile dasd_global_profile = {
 | 
				
			||||||
static struct dentry *dasd_global_profile_dentry;
 | 
						.lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
static struct dentry *dasd_debugfs_global_entry;
 | 
					static struct dentry *dasd_debugfs_global_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -696,11 +697,13 @@ static void dasd_profile_start(struct dasd_block *block,
 | 
				
			||||||
			if (++counter >= 31)
 | 
								if (++counter >= 31)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dasd_global_profile_level) {
 | 
						spin_lock(&dasd_global_profile.lock);
 | 
				
			||||||
		dasd_global_profile_data.dasd_io_nr_req[counter]++;
 | 
						if (dasd_global_profile.data) {
 | 
				
			||||||
 | 
							dasd_global_profile.data->dasd_io_nr_req[counter]++;
 | 
				
			||||||
		if (rq_data_dir(req) == READ)
 | 
							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);
 | 
						spin_lock(&block->profile.lock);
 | 
				
			||||||
	if (block->profile.data) {
 | 
						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(irqtime / sectors, irqtimeps_ind);
 | 
				
			||||||
	dasd_profile_counter(endtime, endtime_ind);
 | 
						dasd_profile_counter(endtime, endtime_ind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dasd_global_profile_level) {
 | 
						spin_lock(&dasd_global_profile.lock);
 | 
				
			||||||
		dasd_profile_end_add_data(&dasd_global_profile_data,
 | 
						if (dasd_global_profile.data) {
 | 
				
			||||||
 | 
							dasd_profile_end_add_data(dasd_global_profile.data,
 | 
				
			||||||
					  cqr->startdev != block->base,
 | 
										  cqr->startdev != block->base,
 | 
				
			||||||
					  cqr->cpmode == 1,
 | 
										  cqr->cpmode == 1,
 | 
				
			||||||
					  rq_data_dir(req) == READ,
 | 
										  rq_data_dir(req) == READ,
 | 
				
			||||||
| 
						 | 
					@ -835,6 +839,7 @@ static void dasd_profile_end(struct dasd_block *block,
 | 
				
			||||||
					  irqtime_ind, irqtimeps_ind,
 | 
										  irqtime_ind, irqtimeps_ind,
 | 
				
			||||||
					  endtime_ind);
 | 
										  endtime_ind);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&dasd_global_profile.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&block->profile.lock);
 | 
						spin_lock(&block->profile.lock);
 | 
				
			||||||
	if (block->profile.data)
 | 
						if (block->profile.data)
 | 
				
			||||||
| 
						 | 
					@ -876,12 +881,6 @@ void dasd_profile_reset(struct dasd_profile *profile)
 | 
				
			||||||
	spin_unlock_bh(&profile->lock);
 | 
						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)
 | 
					int dasd_profile_on(struct dasd_profile *profile)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dasd_profile_info *data;
 | 
						struct dasd_profile_info *data;
 | 
				
			||||||
| 
						 | 
					@ -949,12 +948,20 @@ static ssize_t dasd_stats_write(struct file *file,
 | 
				
			||||||
		dasd_profile_reset(prof);
 | 
							dasd_profile_reset(prof);
 | 
				
			||||||
	} else if (strncmp(str, "on", 2) == 0) {
 | 
						} else if (strncmp(str, "on", 2) == 0) {
 | 
				
			||||||
		rc = dasd_profile_on(prof);
 | 
							rc = dasd_profile_on(prof);
 | 
				
			||||||
		if (!rc)
 | 
							if (rc)
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
		rc = user_len;
 | 
							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) {
 | 
						} else if (strncmp(str, "off", 3) == 0) {
 | 
				
			||||||
 | 
							if (prof == &dasd_global_profile)
 | 
				
			||||||
 | 
								dasd_global_profile_level = DASD_PROFILE_OFF;
 | 
				
			||||||
		dasd_profile_off(prof);
 | 
							dasd_profile_off(prof);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		rc = -EINVAL;
 | 
							rc = -EINVAL;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	vfree(buffer);
 | 
						vfree(buffer);
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1044,57 +1051,6 @@ static const struct file_operations dasd_stats_raw_fops = {
 | 
				
			||||||
	.write		= dasd_stats_write,
 | 
						.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,
 | 
					static void dasd_profile_init(struct dasd_profile *profile,
 | 
				
			||||||
			      struct dentry *base_dentry)
 | 
								      struct dentry *base_dentry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1123,20 +1079,16 @@ static void dasd_profile_exit(struct dasd_profile *profile)
 | 
				
			||||||
static void dasd_statistics_removeroot(void)
 | 
					static void dasd_statistics_removeroot(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dasd_global_profile_level = DASD_PROFILE_OFF;
 | 
						dasd_global_profile_level = DASD_PROFILE_OFF;
 | 
				
			||||||
	debugfs_remove(dasd_global_profile_dentry);
 | 
						dasd_profile_exit(&dasd_global_profile);
 | 
				
			||||||
	dasd_global_profile_dentry = NULL;
 | 
					 | 
				
			||||||
	debugfs_remove(dasd_debugfs_global_entry);
 | 
						debugfs_remove(dasd_debugfs_global_entry);
 | 
				
			||||||
	debugfs_remove(dasd_debugfs_root_entry);
 | 
						debugfs_remove(dasd_debugfs_root_entry);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dasd_statistics_createroot(void)
 | 
					static void dasd_statistics_createroot(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	umode_t mode;
 | 
					 | 
				
			||||||
	struct dentry *pde;
 | 
						struct dentry *pde;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dasd_debugfs_root_entry = NULL;
 | 
						dasd_debugfs_root_entry = NULL;
 | 
				
			||||||
	dasd_debugfs_global_entry = NULL;
 | 
					 | 
				
			||||||
	dasd_global_profile_dentry = NULL;
 | 
					 | 
				
			||||||
	pde = debugfs_create_dir("dasd", NULL);
 | 
						pde = debugfs_create_dir("dasd", NULL);
 | 
				
			||||||
	if (!pde || IS_ERR(pde))
 | 
						if (!pde || IS_ERR(pde))
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
| 
						 | 
					@ -1145,13 +1097,7 @@ static void dasd_statistics_createroot(void)
 | 
				
			||||||
	if (!pde || IS_ERR(pde))
 | 
						if (!pde || IS_ERR(pde))
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	dasd_debugfs_global_entry = pde;
 | 
						dasd_debugfs_global_entry = pde;
 | 
				
			||||||
 | 
						dasd_profile_init(&dasd_global_profile, dasd_debugfs_global_entry);
 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize)
 | 
				
			||||||
#define DASD_PROFILE_GLOBAL_ONLY 2
 | 
					#define DASD_PROFILE_GLOBAL_ONLY 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern debug_info_t *dasd_debug_area;
 | 
					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 unsigned int dasd_global_profile_level;
 | 
				
			||||||
extern const struct block_device_operations dasd_device_operations;
 | 
					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 *);
 | 
					void dasd_profile_reset(struct dasd_profile *);
 | 
				
			||||||
int dasd_profile_on(struct dasd_profile *);
 | 
					int dasd_profile_on(struct dasd_profile *);
 | 
				
			||||||
void dasd_profile_off(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);
 | 
					char *dasd_get_user_string(const char __user *, size_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* externals in dasd_devmap.c */
 | 
					/* externals in dasd_devmap.c */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,14 +212,15 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
 | 
				
			||||||
	struct dasd_profile_info *prof;
 | 
						struct dasd_profile_info *prof;
 | 
				
			||||||
	int factor;
 | 
						int factor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check for active profiling */
 | 
						spin_lock_bh(&dasd_global_profile.lock);
 | 
				
			||||||
	if (!dasd_global_profile_level) {
 | 
						prof = dasd_global_profile.data;
 | 
				
			||||||
 | 
						if (!prof) {
 | 
				
			||||||
 | 
							spin_unlock_bh(&dasd_global_profile.lock);
 | 
				
			||||||
		seq_printf(m, "Statistics are off - they might be "
 | 
							seq_printf(m, "Statistics are off - they might be "
 | 
				
			||||||
				    "switched on using 'echo set on > "
 | 
									    "switched on using 'echo set on > "
 | 
				
			||||||
				    "/proc/dasd/statistics'\n");
 | 
									    "/proc/dasd/statistics'\n");
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	prof = &dasd_global_profile_data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* prevent counter 'overflow' on output */
 | 
						/* prevent counter 'overflow' on output */
 | 
				
			||||||
	for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
 | 
						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);
 | 
						dasd_statistics_array(m, prof->dasd_io_time3, factor);
 | 
				
			||||||
	seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
 | 
						seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
 | 
				
			||||||
	dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
 | 
						dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
 | 
				
			||||||
 | 
						spin_unlock_bh(&dasd_global_profile.lock);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	seq_printf(m, "Statistics are not activated in this kernel\n");
 | 
						seq_printf(m, "Statistics are not activated in this kernel\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -291,14 +293,19 @@ static ssize_t dasd_stats_proc_write(struct file *file,
 | 
				
			||||||
				dasd_stats_all_block_off();
 | 
									dasd_stats_all_block_off();
 | 
				
			||||||
				goto out_error;
 | 
									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;
 | 
								dasd_global_profile_level = DASD_PROFILE_ON;
 | 
				
			||||||
			pr_info("The statistics feature has been switched "
 | 
								pr_info("The statistics feature has been switched "
 | 
				
			||||||
				"on\n");
 | 
									"on\n");
 | 
				
			||||||
		} else if (strcmp(str, "off") == 0) {
 | 
							} 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_level = DASD_PROFILE_OFF;
 | 
				
			||||||
			dasd_global_profile_reset();
 | 
								dasd_profile_off(&dasd_global_profile);
 | 
				
			||||||
			dasd_stats_all_block_off();
 | 
								dasd_stats_all_block_off();
 | 
				
			||||||
			pr_info("The statistics feature has been switched "
 | 
								pr_info("The statistics feature has been switched "
 | 
				
			||||||
				"off\n");
 | 
									"off\n");
 | 
				
			||||||
| 
						 | 
					@ -306,7 +313,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
 | 
				
			||||||
			goto out_parse_error;
 | 
								goto out_parse_error;
 | 
				
			||||||
	} else if (strncmp(str, "reset", 5) == 0) {
 | 
						} else if (strncmp(str, "reset", 5) == 0) {
 | 
				
			||||||
		/* reset the statistics */
 | 
							/* reset the statistics */
 | 
				
			||||||
		dasd_global_profile_reset();
 | 
							dasd_profile_reset(&dasd_global_profile);
 | 
				
			||||||
		dasd_stats_all_block_reset();
 | 
							dasd_stats_all_block_reset();
 | 
				
			||||||
		pr_info("The statistics have been reset\n");
 | 
							pr_info("The statistics have been reset\n");
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -438,6 +438,12 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
 | 
				
			||||||
			pr_info("All DCSSs that map to device %s are "
 | 
								pr_info("All DCSSs that map to device %s are "
 | 
				
			||||||
				"saved\n", dev_info->segment_name);
 | 
									"saved\n", dev_info->segment_name);
 | 
				
			||||||
			list_for_each_entry(entry, &dev_info->seg_list, lh) {
 | 
								list_for_each_entry(entry, &dev_info->seg_list, lh) {
 | 
				
			||||||
 | 
									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);
 | 
										segment_save(entry->segment_name);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}  else {
 | 
							}  else {
 | 
				
			||||||
| 
						 | 
					@ -797,6 +803,11 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
 | 
				
			||||||
		pr_info("Device %s has become idle and is being saved "
 | 
							pr_info("Device %s has become idle and is being saved "
 | 
				
			||||||
			"now\n", dev_info->segment_name);
 | 
								"now\n", dev_info->segment_name);
 | 
				
			||||||
		list_for_each_entry(entry, &dev_info->seg_list, lh) {
 | 
							list_for_each_entry(entry, &dev_info->seg_list, lh) {
 | 
				
			||||||
 | 
								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);
 | 
									segment_save(entry->segment_name);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		dev_info->save_pending = 0;
 | 
							dev_info->save_pending = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,10 +200,9 @@ int hmcdrv_ftp_probe(void)
 | 
				
			||||||
	rc = hmcdrv_ftp_startup();
 | 
						rc = hmcdrv_ftp_startup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = hmcdrv_ftp_do(&ftp);
 | 
						rc = hmcdrv_ftp_do(&ftp);
 | 
				
			||||||
	free_page((unsigned long) ftp.buf);
 | 
					 | 
				
			||||||
	hmcdrv_ftp_shutdown();
 | 
						hmcdrv_ftp_shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (rc) {
 | 
						switch (rc) {
 | 
				
			||||||
| 
						 | 
					@ -216,7 +215,8 @@ int hmcdrv_ftp_probe(void)
 | 
				
			||||||
			rc = 0; /* clear length (success) */
 | 
								rc = 0; /* clear length (success) */
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	} /* switch */
 | 
						} /* switch */
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						free_page((unsigned long) ftp.buf);
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(hmcdrv_ftp_probe);
 | 
					EXPORT_SYMBOL(hmcdrv_ftp_probe);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,6 @@
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/moduleparam.h>
 | 
					#include <linux/moduleparam.h>
 | 
				
			||||||
#include <linux/version.h>
 | 
					 | 
				
			||||||
#include <linux/stat.h>
 | 
					#include <linux/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "hmcdrv_ftp.h"
 | 
					#include "hmcdrv_ftp.h"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,26 +20,31 @@ struct read_info_sccb {
 | 
				
			||||||
	struct	sccb_header header;	/* 0-7 */
 | 
						struct	sccb_header header;	/* 0-7 */
 | 
				
			||||||
	u16	rnmax;			/* 8-9 */
 | 
						u16	rnmax;			/* 8-9 */
 | 
				
			||||||
	u8	rnsize;			/* 10 */
 | 
						u8	rnsize;			/* 10 */
 | 
				
			||||||
	u8	_reserved0[16 - 11];	/* 11-15 */
 | 
						u8	_pad_11[16 - 11];	/* 11-15 */
 | 
				
			||||||
	u16	ncpurl;			/* 16-17 */
 | 
						u16	ncpurl;			/* 16-17 */
 | 
				
			||||||
	u16	cpuoff;			/* 18-19 */
 | 
						u16	cpuoff;			/* 18-19 */
 | 
				
			||||||
	u8	_reserved7[24 - 20];	/* 20-23 */
 | 
						u8	_pad_20[24 - 20];	/* 20-23 */
 | 
				
			||||||
	u8	loadparm[8];		/* 24-31 */
 | 
						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 */
 | 
						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 */
 | 
						u32	ibc;			/* 76-79 */
 | 
				
			||||||
	u8	_reserved2b[84 - 80];	/* 80-83 */
 | 
						u8	_pad80[84 - 80];	/* 80-83 */
 | 
				
			||||||
	u8	fac84;			/* 84 */
 | 
						u8	fac84;			/* 84 */
 | 
				
			||||||
	u8	fac85;			/* 85 */
 | 
						u8	fac85;			/* 85 */
 | 
				
			||||||
	u8	_reserved3[91 - 86];	/* 86-90 */
 | 
						u8	_pad_86[91 - 86];	/* 86-90 */
 | 
				
			||||||
	u8	flags;			/* 91 */
 | 
						u8	flags;			/* 91 */
 | 
				
			||||||
	u8	_reserved4[100 - 92];	/* 92-99 */
 | 
						u8	_pad_92[100 - 92];	/* 92-99 */
 | 
				
			||||||
	u32	rnsize2;		/* 100-103 */
 | 
						u32	rnsize2;		/* 100-103 */
 | 
				
			||||||
	u64	rnmax2;			/* 104-111 */
 | 
						u64	rnmax2;			/* 104-111 */
 | 
				
			||||||
	u8	_reserved5[120 - 112];	/* 112-119 */
 | 
						u8	_pad_112[120 - 112];	/* 112-119 */
 | 
				
			||||||
	u16	hcpua;			/* 120-121 */
 | 
						u16	hcpua;			/* 120-121 */
 | 
				
			||||||
	u8	_reserved6[4096 - 122];	/* 122-4095 */
 | 
						u8	_pad_122[4096 - 122];	/* 122-4095 */
 | 
				
			||||||
} __packed __aligned(PAGE_SIZE);
 | 
					} __packed __aligned(PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
 | 
					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 struct sclp_ipl_info sclp_ipl_info;
 | 
				
			||||||
static unsigned char sclp_siif;
 | 
					static unsigned char sclp_siif;
 | 
				
			||||||
static u32 sclp_ibc;
 | 
					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;
 | 
					u64 sclp_facilities;
 | 
				
			||||||
u8 sclp_fac84;
 | 
					u8 sclp_fac84;
 | 
				
			||||||
| 
						 | 
					@ -128,7 +137,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
 | 
				
			||||||
	boot_cpu_address = stap();
 | 
						boot_cpu_address = stap();
 | 
				
			||||||
	cpue = (void *)sccb + sccb->cpuoff;
 | 
						cpue = (void *)sccb + sccb->cpuoff;
 | 
				
			||||||
	for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
 | 
						for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
 | 
				
			||||||
		if (boot_cpu_address != cpue->address)
 | 
							if (boot_cpu_address != cpue->core_id)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		sclp_siif = cpue->siif;
 | 
							sclp_siif = cpue->siif;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -139,6 +148,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
 | 
				
			||||||
	if (sccb->flags & 0x2)
 | 
						if (sccb->flags & 0x2)
 | 
				
			||||||
		sclp_ipl_info.has_dump = 1;
 | 
							sclp_ipl_info.has_dump = 1;
 | 
				
			||||||
	memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
 | 
						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)
 | 
					bool __init sclp_has_linemode(void)
 | 
				
			||||||
| 
						 | 
					@ -178,6 +192,21 @@ unsigned int sclp_get_ibc(void)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(sclp_get_ibc);
 | 
					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
 | 
					 * This function will be called after sclp_facilities_detect(), which gets
 | 
				
			||||||
 * called from early.c code. The sclp_facilities_detect() function retrieves
 | 
					 * called from early.c code. The sclp_facilities_detect() function retrieves
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -773,13 +773,11 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
 | 
				
			||||||
			"occurred\n");
 | 
								"occurred\n");
 | 
				
			||||||
		return tape_34xx_erp_failed(request, -EIO);
 | 
							return tape_34xx_erp_failed(request, -EIO);
 | 
				
			||||||
	case 0x57:
 | 
						case 0x57:
 | 
				
			||||||
		if (device->cdev->id.driver_info == tape_3480) {
 | 
							/*
 | 
				
			||||||
			/* Attention intercept. */
 | 
							 * 3480: Attention intercept.
 | 
				
			||||||
 | 
							 * 3490: Global status intercept.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		return tape_34xx_erp_retry(request);
 | 
							return tape_34xx_erp_retry(request);
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			/* Global status intercept. */
 | 
					 | 
				
			||||||
			return tape_34xx_erp_retry(request);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	case 0x5a:
 | 
						case 0x5a:
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Tape length incompatible. The tape inserted is too long,
 | 
							 * Tape length incompatible. The tape inserted is too long,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct subchannel_id uninitialized_var(schid);
 | 
						struct subchannel_id uninitialized_var(schid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s390_reset_system(NULL, NULL);
 | 
						s390_reset_system(NULL, NULL, NULL);
 | 
				
			||||||
	if (reipl_find_schid(devid, &schid) != 0)
 | 
						if (reipl_find_schid(devid, &schid) != 0)
 | 
				
			||||||
		panic("IPL Device not found\n");
 | 
							panic("IPL Device not found\n");
 | 
				
			||||||
	do_reipl_asm(*((__u32*)&schid));
 | 
						do_reipl_asm(*((__u32*)&schid));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,11 +38,6 @@ void idset_free(struct idset *set)
 | 
				
			||||||
	vfree(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)
 | 
					void idset_fill(struct idset *set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id));
 | 
						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);
 | 
						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)
 | 
					int idset_is_empty(struct idset *set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return bitmap_empty(set->bitmap, set->num_ssid * set->num_id);
 | 
						return bitmap_empty(set->bitmap, set->num_ssid * set->num_id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,6 @@
 | 
				
			||||||
struct idset;
 | 
					struct idset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void idset_free(struct idset *set);
 | 
					void idset_free(struct idset *set);
 | 
				
			||||||
void idset_clear(struct idset *set);
 | 
					 | 
				
			||||||
void idset_fill(struct idset *set);
 | 
					void idset_fill(struct idset *set);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct idset *idset_sch_new(void);
 | 
					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(struct idset *set, struct subchannel_id id);
 | 
				
			||||||
void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid);
 | 
					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_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);
 | 
					int idset_is_empty(struct idset *set);
 | 
				
			||||||
void idset_add_set(struct idset *to, struct idset *from);
 | 
					void idset_add_set(struct idset *to, struct idset *from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,6 +203,24 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
 | 
				
			||||||
	return reg1;
 | 
						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.
 | 
					 * ap_reset_queue(): Reset adjunct processor queue.
 | 
				
			||||||
 * @qid: The AP queue number
 | 
					 * @qid: The AP queue number
 | 
				
			||||||
| 
						 | 
					@ -1006,6 +1024,51 @@ void ap_bus_force_rescan(void)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(ap_bus_force_rescan);
 | 
					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.
 | 
					 * 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 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[] = {
 | 
					static struct bus_attribute *const ap_bus_attrs[] = {
 | 
				
			||||||
	&bus_attr_ap_domain,
 | 
						&bus_attr_ap_domain,
 | 
				
			||||||
	&bus_attr_ap_control_domain_mask,
 | 
						&bus_attr_ap_control_domain_mask,
 | 
				
			||||||
| 
						 | 
					@ -1128,50 +1227,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
 | 
				
			||||||
	&bus_attr_poll_thread,
 | 
						&bus_attr_poll_thread,
 | 
				
			||||||
	&bus_attr_ap_interrupts,
 | 
						&bus_attr_ap_interrupts,
 | 
				
			||||||
	&bus_attr_poll_timeout,
 | 
						&bus_attr_poll_timeout,
 | 
				
			||||||
 | 
						&bus_attr_ap_max_domain_id,
 | 
				
			||||||
	NULL,
 | 
						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.
 | 
					 * ap_query_configuration(): Query AP configuration information.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -1434,9 +1493,6 @@ static void ap_scan_bus(struct work_struct *unused)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 11:
 | 
					 | 
				
			||||||
			ap_dev->device_type = 10;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			ap_dev->device_type = device_type;
 | 
								ap_dev->device_type = device_type;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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_CEX3A	8
 | 
				
			||||||
#define AP_DEVICE_TYPE_CEX3C	9
 | 
					#define AP_DEVICE_TYPE_CEX3C	9
 | 
				
			||||||
#define AP_DEVICE_TYPE_CEX4	10
 | 
					#define AP_DEVICE_TYPE_CEX4	10
 | 
				
			||||||
 | 
					#define AP_DEVICE_TYPE_CEX5	11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Known function facilities
 | 
					 * Known function facilities
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,7 @@ struct ica_z90_status {
 | 
				
			||||||
#define ZCRYPT_CEX3C		7
 | 
					#define ZCRYPT_CEX3C		7
 | 
				
			||||||
#define ZCRYPT_CEX3A		8
 | 
					#define ZCRYPT_CEX3A		8
 | 
				
			||||||
#define ZCRYPT_CEX4	       10
 | 
					#define ZCRYPT_CEX4	       10
 | 
				
			||||||
 | 
					#define ZCRYPT_CEX5	       11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Large random numbers are pulled in 4096 byte chunks from the crypto cards
 | 
					 * Large random numbers are pulled in 4096 byte chunks from the crypto cards
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CEX4A_SPEED_RATING	900	 /* TODO new card, new speed rating */
 | 
					#define CEX4A_SPEED_RATING	900	 /* TODO new card, new speed rating */
 | 
				
			||||||
#define CEX4C_SPEED_RATING	6500	 /* 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 CEX4A_MAX_MESSAGE_SIZE	MSGTYPE50_CRB3_MAX_MSG_SIZE
 | 
				
			||||||
#define CEX4C_MAX_MESSAGE_SIZE	MSGTYPE06_MAX_MSG_SIZE
 | 
					#define CEX4C_MAX_MESSAGE_SIZE	MSGTYPE06_MAX_MSG_SIZE
 | 
				
			||||||
| 
						 | 
					@ -39,6 +43,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct ap_device_id zcrypt_cex4_ids[] = {
 | 
					static struct ap_device_id zcrypt_cex4_ids[] = {
 | 
				
			||||||
	{ AP_DEVICE(AP_DEVICE_TYPE_CEX4)  },
 | 
						{ AP_DEVICE(AP_DEVICE_TYPE_CEX4)  },
 | 
				
			||||||
 | 
						{ AP_DEVICE(AP_DEVICE_TYPE_CEX5)  },
 | 
				
			||||||
	{ /* end of list */ },
 | 
						{ /* end of list */ },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,11 +75,18 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (ap_dev->device_type) {
 | 
						switch (ap_dev->device_type) {
 | 
				
			||||||
	case AP_DEVICE_TYPE_CEX4:
 | 
						case AP_DEVICE_TYPE_CEX4:
 | 
				
			||||||
 | 
						case AP_DEVICE_TYPE_CEX5:
 | 
				
			||||||
		if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
 | 
							if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
 | 
				
			||||||
			zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
 | 
								zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
 | 
				
			||||||
			if (!zdev)
 | 
								if (!zdev)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
 | 
								if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
 | 
				
			||||||
				zdev->type_string = "CEX4A";
 | 
									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->user_space_type = ZCRYPT_CEX3A;
 | 
				
			||||||
			zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
 | 
								zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
 | 
				
			||||||
			if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
 | 
								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;
 | 
										CEX4A_MAX_MOD_SIZE_2K;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			zdev->short_crt = 1;
 | 
								zdev->short_crt = 1;
 | 
				
			||||||
			zdev->speed_rating = CEX4A_SPEED_RATING;
 | 
					 | 
				
			||||||
			zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
 | 
								zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
 | 
				
			||||||
							   MSGTYPE50_VARIANT_DEFAULT);
 | 
												   MSGTYPE50_VARIANT_DEFAULT);
 | 
				
			||||||
		} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
 | 
							} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
 | 
				
			||||||
			zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
 | 
								zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
 | 
				
			||||||
			if (!zdev)
 | 
								if (!zdev)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
 | 
								if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
 | 
				
			||||||
				zdev->type_string = "CEX4C";
 | 
									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->user_space_type = ZCRYPT_CEX3C;
 | 
				
			||||||
			zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
 | 
								zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
 | 
				
			||||||
			zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
 | 
								zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
 | 
				
			||||||
			zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
 | 
								zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
 | 
				
			||||||
			zdev->short_crt = 0;
 | 
								zdev->short_crt = 0;
 | 
				
			||||||
			zdev->speed_rating = CEX4C_SPEED_RATING;
 | 
					 | 
				
			||||||
			zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
 | 
								zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
 | 
				
			||||||
							   MSGTYPE06_VARIANT_DEFAULT);
 | 
												   MSGTYPE06_VARIANT_DEFAULT);
 | 
				
			||||||
		} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
 | 
							} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
 | 
				
			||||||
			zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
 | 
								zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
 | 
				
			||||||
			if (!zdev)
 | 
								if (!zdev)
 | 
				
			||||||
				return -ENOMEM;
 | 
									return -ENOMEM;
 | 
				
			||||||
 | 
								if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
 | 
				
			||||||
				zdev->type_string = "CEX4P";
 | 
									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->user_space_type = ZCRYPT_CEX4;
 | 
				
			||||||
			zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
 | 
								zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
 | 
				
			||||||
			zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
 | 
								zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
 | 
				
			||||||
			zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
 | 
								zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
 | 
				
			||||||
			zdev->short_crt = 0;
 | 
								zdev->short_crt = 0;
 | 
				
			||||||
			zdev->speed_rating = CEX4C_SPEED_RATING;
 | 
					 | 
				
			||||||
			zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
 | 
								zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
 | 
				
			||||||
							MSGTYPE06_VARIANT_EP11);
 | 
												MSGTYPE06_VARIANT_EP11);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					 * This HVC device driver provides terminal access using
 | 
				
			||||||
 * z/VM IUCV communication paths.
 | 
					 * z/VM IUCV communication paths.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright IBM Corp. 2008, 2009
 | 
					 * Copyright IBM Corp. 2008, 2013
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Author(s):	Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
 | 
					 * 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)
 | 
					#define IUCV_HVC_CON_IDX	(0)
 | 
				
			||||||
/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
 | 
					/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
 | 
				
			||||||
#define MAX_VMID_FILTER		(500)
 | 
					#define MAX_VMID_FILTER		(500)
 | 
				
			||||||
 | 
					#define FILTER_WILDCARD_CHAR	'*'
 | 
				
			||||||
static size_t hvc_iucv_filter_size;
 | 
					static size_t hvc_iucv_filter_size;
 | 
				
			||||||
static void *hvc_iucv_filter;
 | 
					static void *hvc_iucv_filter;
 | 
				
			||||||
static const char *hvc_iucv_filter_string;
 | 
					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
 | 
					 * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID
 | 
				
			||||||
 * @ipvmid:	Originating z/VM user ID (right padded with blanks)
 | 
					 * @ipvmid:	Originating z/VM user ID (right padded with blanks)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise
 | 
					 * Returns 0 if the z/VM user ID that is specified with @ipvmid is permitted to
 | 
				
			||||||
 * non-zero.
 | 
					 * connect, otherwise non-zero.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int hvc_iucv_filter_connreq(u8 ipvmid[8])
 | 
					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 */
 | 
						/* Note: default policy is ACCEPT if no filter is set */
 | 
				
			||||||
	if (!hvc_iucv_filter_size)
 | 
						if (!hvc_iucv_filter_size)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < hvc_iucv_filter_size; i++)
 | 
						for (i = 0; i < hvc_iucv_filter_size; i++) {
 | 
				
			||||||
		if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8))
 | 
							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 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 1;
 | 
						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
 | 
					 * 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
 | 
					 * @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)
 | 
					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')
 | 
						if (filter[len - 1] == '\n')
 | 
				
			||||||
		len--;
 | 
							len--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* prohibit filter entries containing the wildcard character only */
 | 
				
			||||||
 | 
						if (len == 1 && *filter == FILTER_WILDCARD_CHAR)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len > 8)
 | 
						if (len > 8)
 | 
				
			||||||
		return ERR_PTR(-EINVAL);
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,11 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 | 
				
			||||||
#include <linux/compiler-gcc.h>
 | 
					#include <linux/compiler-gcc.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CC_USING_HOTPATCH
 | 
				
			||||||
 | 
					#define notrace __attribute__((hotpatch(0,0)))
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
#define notrace __attribute__((no_instrument_function))
 | 
					#define notrace __attribute__((no_instrument_function))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Intel compiler defines __GNUC__. So we will overwrite implementations
 | 
					/* Intel compiler defines __GNUC__. So we will overwrite implementations
 | 
				
			||||||
 * coming from above header files here
 | 
					 * coming from above header files here
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,8 +13,8 @@ obj-y     = fork.o exec_domain.o panic.o \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
# Do not trace debug files and internal ftrace files
 | 
					# Do not trace debug files and internal ftrace files
 | 
				
			||||||
CFLAGS_REMOVE_cgroup-debug.o = -pg
 | 
					CFLAGS_REMOVE_cgroup-debug.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
CFLAGS_REMOVE_irq_work.o = -pg
 | 
					CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# cond_syscall is currently not LTO compatible
 | 
					# cond_syscall is currently not LTO compatible
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
CFLAGS_REMOVE_core.o = -pg
 | 
					CFLAGS_REMOVE_core.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y := core.o ring_buffer.o callchain.o
 | 
					obj-y := core.o ring_buffer.o callchain.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,10 @@
 | 
				
			||||||
obj-y += mutex.o semaphore.o rwsem.o
 | 
					obj-y += mutex.o semaphore.o rwsem.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
CFLAGS_REMOVE_lockdep.o = -pg
 | 
					CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
CFLAGS_REMOVE_lockdep_proc.o = -pg
 | 
					CFLAGS_REMOVE_lockdep_proc.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
CFLAGS_REMOVE_mutex-debug.o = -pg
 | 
					CFLAGS_REMOVE_mutex-debug.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
CFLAGS_REMOVE_rtmutex-debug.o = -pg
 | 
					CFLAGS_REMOVE_rtmutex-debug.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 | 
					obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
CFLAGS_REMOVE_clock.o = -pg
 | 
					CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 | 
					ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,11 +3,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
 | 
					ORIG_CFLAGS := $(KBUILD_CFLAGS)
 | 
				
			||||||
KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
 | 
					KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FTRACE_SELFTEST
 | 
					ifdef CONFIG_FTRACE_SELFTEST
 | 
				
			||||||
# selftest needs instrumentation
 | 
					# selftest needs instrumentation
 | 
				
			||||||
CFLAGS_trace_selftest_dynamic.o = -pg
 | 
					CFLAGS_trace_selftest_dynamic.o = $(CC_FLAGS_FTRACE)
 | 
				
			||||||
obj-y += trace_selftest_dynamic.o
 | 
					obj-y += trace_selftest_dynamic.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_FUNCTION_TRACER
 | 
					ifdef CONFIG_FUNCTION_TRACER
 | 
				
			||||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
 | 
					ORIG_CFLAGS := $(KBUILD_CFLAGS)
 | 
				
			||||||
KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
 | 
					KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib-y := ctype.o string.o vsprintf.o cmdline.o \
 | 
					lib-y := ctype.o string.o vsprintf.o cmdline.o \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,8 @@ sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH
 | 
				
			||||||
recordmcount_source := $(srctree)/scripts/recordmcount.pl
 | 
					recordmcount_source := $(srctree)/scripts/recordmcount.pl
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
cmd_record_mcount =						\
 | 
					cmd_record_mcount =						\
 | 
				
			||||||
	if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then	\
 | 
						if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" =	\
 | 
				
			||||||
 | 
						     "$(CC_FLAGS_FTRACE)" ]; then			\
 | 
				
			||||||
		$(sub_cmd_record_mcount)			\
 | 
							$(sub_cmd_record_mcount)			\
 | 
				
			||||||
	fi;
 | 
						fi;
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,8 +242,13 @@ if ($arch eq "x86_64") {
 | 
				
			||||||
    $cc .= " -m32";
 | 
					    $cc .= " -m32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} elsif ($arch eq "s390" && $bits == 64) {
 | 
					} elsif ($arch eq "s390" && $bits == 64) {
 | 
				
			||||||
 | 
					    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_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
 | 
				
			||||||
	$mcount_adjust = -14;
 | 
						$mcount_adjust = -14;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    $alignment = 8;
 | 
					    $alignment = 8;
 | 
				
			||||||
    $type = ".quad";
 | 
					    $type = ".quad";
 | 
				
			||||||
    $ld .= " -m elf64_s390";
 | 
					    $ld .= " -m elf64_s390";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue