diff options
67 files changed, 1521 insertions, 1500 deletions
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 462321c1aeea..08911b5c6b0e 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt | |||
@@ -26,11 +26,6 @@ The Linux for s/390 & z/Architecture Kernel Task Structure | |||
26 | Register Usage & Stackframes on Linux for s/390 & z/Architecture | 26 | Register Usage & Stackframes on Linux for s/390 & z/Architecture |
27 | A sample program with comments | 27 | A sample program with comments |
28 | Compiling programs for debugging on Linux for s/390 & z/Architecture | 28 | Compiling programs for debugging on Linux for s/390 & z/Architecture |
29 | Figuring out gcc compile errors | ||
30 | Debugging Tools | ||
31 | objdump | ||
32 | strace | ||
33 | Performance Debugging | ||
34 | Debugging under VM | 29 | Debugging under VM |
35 | s/390 & z/Architecture IO Overview | 30 | s/390 & z/Architecture IO Overview |
36 | Debugging IO on s/390 & z/Architecture under VM | 31 | Debugging IO on s/390 & z/Architecture under VM |
@@ -114,28 +109,25 @@ s/390 z/Architecture | |||
114 | 109 | ||
115 | 16-17 16-17 Address Space Control | 110 | 16-17 16-17 Address Space Control |
116 | 111 | ||
117 | 00 Primary Space Mode when DAT on | 112 | 00 Primary Space Mode: |
118 | The linux kernel currently runs in this mode, CR1 is affiliated with | 113 | The register CR1 contains the primary address-space control ele- |
119 | this mode & points to the primary segment table origin etc. | 114 | ment (PASCE), which points to the primary space region/segment |
120 | 115 | table origin. | |
121 | 01 Access register mode this mode is used in functions to | 116 | |
122 | copy data between kernel & user space. | 117 | 01 Access register mode |
123 | 118 | ||
124 | 10 Secondary space mode not used in linux however CR7 the | 119 | 10 Secondary Space Mode: |
125 | register affiliated with this mode is & this & normally | 120 | The register CR7 contains the secondary address-space control |
126 | CR13=CR7 to allow us to copy data between kernel & user space. | 121 | element (SASCE), which points to the secondary space region or |
127 | We do this as follows: | 122 | segment table origin. |
128 | We set ar2 to 0 to designate its | 123 | |
129 | affiliated gpr ( gpr2 )to point to primary=kernel space. | 124 | 11 Home Space Mode: |
130 | We set ar4 to 1 to designate its | 125 | The register CR13 contains the home space address-space control |
131 | affiliated gpr ( gpr4 ) to point to secondary=home=user space | 126 | element (HASCE), which points to the home space region/segment |
132 | & then essentially do a memcopy(gpr2,gpr4,size) to | 127 | table origin. |
133 | copy data between the address spaces, the reason we use home space for the | 128 | |
134 | kernel & don't keep secondary space free is that code will not run in | 129 | See "Address Spaces on Linux for s/390 & z/Architecture" below |
135 | secondary space. | 130 | for more information about address space usage in Linux. |
136 | |||
137 | 11 Home Space Mode all user programs run in this mode. | ||
138 | it is affiliated with CR13. | ||
139 | 131 | ||
140 | 18-19 18-19 Condition codes (CC) | 132 | 18-19 18-19 Condition codes (CC) |
141 | 133 | ||
@@ -249,9 +241,9 @@ currently 4TB of physical memory currently on z/Architecture. | |||
249 | Address Spaces on Linux for s/390 & z/Architecture | 241 | Address Spaces on Linux for s/390 & z/Architecture |
250 | ================================================== | 242 | ================================================== |
251 | 243 | ||
252 | Our addressing scheme is as follows | 244 | Our addressing scheme is basically as follows: |
253 | |||
254 | 245 | ||
246 | Primary Space Home Space | ||
255 | Himem 0x7fffffff 2GB on s/390 ***************** **************** | 247 | Himem 0x7fffffff 2GB on s/390 ***************** **************** |
256 | currently 0x3ffffffffff (2^42)-1 * User Stack * * * | 248 | currently 0x3ffffffffff (2^42)-1 * User Stack * * * |
257 | on z/Architecture. ***************** * * | 249 | on z/Architecture. ***************** * * |
@@ -264,9 +256,46 @@ on z/Architecture. ***************** * * | |||
264 | * Sections * * * | 256 | * Sections * * * |
265 | 0x00000000 ***************** **************** | 257 | 0x00000000 ***************** **************** |
266 | 258 | ||
267 | This also means that we need to look at the PSW problem state bit | 259 | This also means that we need to look at the PSW problem state bit and the |
268 | or the addressing mode to decide whether we are looking at | 260 | addressing mode to decide whether we are looking at user or kernel space. |
269 | user or kernel space. | 261 | |
262 | User space runs in primary address mode (or access register mode within | ||
263 | the vdso code). | ||
264 | |||
265 | The kernel usually also runs in home space mode, however when accessing | ||
266 | user space the kernel switches to primary or secondary address mode if | ||
267 | the mvcos instruction is not available or if a compare-and-swap (futex) | ||
268 | instruction on a user space address is performed. | ||
269 | |||
270 | When also looking at the ASCE control registers, this means: | ||
271 | |||
272 | User space: | ||
273 | - runs in primary or access register mode | ||
274 | - cr1 contains the user asce | ||
275 | - cr7 contains the user asce | ||
276 | - cr13 contains the kernel asce | ||
277 | |||
278 | Kernel space: | ||
279 | - runs in home space mode | ||
280 | - cr1 contains the user or kernel asce | ||
281 | -> the kernel asce is loaded when a uaccess requires primary or | ||
282 | secondary address mode | ||
283 | - cr7 contains the user or kernel asce, (changed with set_fs()) | ||
284 | - cr13 contains the kernel asce | ||
285 | |||
286 | In case of uaccess the kernel changes to: | ||
287 | - primary space mode in case of a uaccess (copy_to_user) and uses | ||
288 | e.g. the mvcp instruction to access user space. However the kernel | ||
289 | will stay in home space mode if the mvcos instruction is available | ||
290 | - secondary space mode in case of futex atomic operations, so that the | ||
291 | instructions come from primary address space and data from secondary | ||
292 | space | ||
293 | |||
294 | In case of KVM, the kernel runs in home space mode, but cr1 gets switched | ||
295 | to contain the gmap asce before the SIE instruction gets executed. When | ||
296 | the SIE instruction is finished, cr1 will be switched back to contain the | ||
297 | user asce. | ||
298 | |||
270 | 299 | ||
271 | Virtual Addresses on s/390 & z/Architecture | 300 | Virtual Addresses on s/390 & z/Architecture |
272 | =========================================== | 301 | =========================================== |
@@ -706,376 +735,7 @@ Debugging with optimisation has since much improved after fixing | |||
706 | some bugs, please make sure you are using gdb-5.0 or later developed | 735 | some bugs, please make sure you are using gdb-5.0 or later developed |
707 | after Nov'2000. | 736 | after Nov'2000. |
708 | 737 | ||
709 | Figuring out gcc compile errors | ||
710 | =============================== | ||
711 | If you are getting a lot of syntax errors compiling a program & the problem | ||
712 | isn't blatantly obvious from the source. | ||
713 | It often helps to just preprocess the file, this is done with the -E | ||
714 | option in gcc. | ||
715 | What this does is that it runs through the very first phase of compilation | ||
716 | ( compilation in gcc is done in several stages & gcc calls many programs to | ||
717 | achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp). | ||
718 | The c preprocessor does the following, it joins all the files #included together | ||
719 | recursively ( #include files can #include other files ) & also the c file you wish to compile. | ||
720 | It puts a fully qualified path of the #included files in a comment & it | ||
721 | does macro expansion. | ||
722 | This is useful for debugging because | ||
723 | 1) You can double check whether the files you expect to be included are the ones | ||
724 | that are being included ( e.g. double check that you aren't going to the i386 asm directory ). | ||
725 | 2) Check that macro definitions aren't clashing with typedefs, | ||
726 | 3) Check that definitions aren't being used before they are being included. | ||
727 | 4) Helps put the line emitting the error under the microscope if it contains macros. | ||
728 | |||
729 | For convenience the Linux kernel's makefile will do preprocessing automatically for you | ||
730 | by suffixing the file you want built with .i ( instead of .o ) | ||
731 | |||
732 | e.g. | ||
733 | from the linux directory type | ||
734 | make arch/s390/kernel/signal.i | ||
735 | this will build | ||
736 | |||
737 | s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer | ||
738 | -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -E arch/s390/kernel/signal.c | ||
739 | > arch/s390/kernel/signal.i | ||
740 | |||
741 | Now look at signal.i you should see something like. | ||
742 | |||
743 | |||
744 | # 1 "/home1/barrow/linux/include/asm/types.h" 1 | ||
745 | typedef unsigned short umode_t; | ||
746 | typedef __signed__ char __s8; | ||
747 | typedef unsigned char __u8; | ||
748 | typedef __signed__ short __s16; | ||
749 | typedef unsigned short __u16; | ||
750 | |||
751 | If instead you are getting errors further down e.g. | ||
752 | unknown instruction:2515 "move.l" or better still unknown instruction:2515 | ||
753 | "Fixme not implemented yet, call Martin" you are probably are attempting to compile some code | ||
754 | meant for another architecture or code that is simply not implemented, with a fixme statement | ||
755 | stuck into the inline assembly code so that the author of the file now knows he has work to do. | ||
756 | To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler ) | ||
757 | use the -S option. | ||
758 | Again for your convenience the Linux kernel's Makefile will hold your hand & | ||
759 | do all this donkey work for you also by building the file with the .s suffix. | ||
760 | e.g. | ||
761 | from the Linux directory type | ||
762 | make arch/s390/kernel/signal.s | ||
763 | |||
764 | s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer | ||
765 | -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -S arch/s390/kernel/signal.c | ||
766 | -o arch/s390/kernel/signal.s | ||
767 | |||
768 | |||
769 | This will output something like, ( please note the constant pool & the useful comments | ||
770 | in the prologue to give you a hand at interpreting it ). | ||
771 | |||
772 | .LC54: | ||
773 | .string "misaligned (__u16 *) in __xchg\n" | ||
774 | .LC57: | ||
775 | .string "misaligned (__u32 *) in __xchg\n" | ||
776 | .L$PG1: # Pool sys_sigsuspend | ||
777 | .LC192: | ||
778 | .long -262401 | ||
779 | .LC193: | ||
780 | .long -1 | ||
781 | .LC194: | ||
782 | .long schedule-.L$PG1 | ||
783 | .LC195: | ||
784 | .long do_signal-.L$PG1 | ||
785 | .align 4 | ||
786 | .globl sys_sigsuspend | ||
787 | .type sys_sigsuspend,@function | ||
788 | sys_sigsuspend: | ||
789 | # leaf function 0 | ||
790 | # automatics 16 | ||
791 | # outgoing args 0 | ||
792 | # need frame pointer 0 | ||
793 | # call alloca 0 | ||
794 | # has varargs 0 | ||
795 | # incoming args (stack) 0 | ||
796 | # function length 168 | ||
797 | STM 8,15,32(15) | ||
798 | LR 0,15 | ||
799 | AHI 15,-112 | ||
800 | BASR 13,0 | ||
801 | .L$CO1: AHI 13,.L$PG1-.L$CO1 | ||
802 | ST 0,0(15) | ||
803 | LR 8,2 | ||
804 | N 5,.LC192-.L$PG1(13) | ||
805 | |||
806 | Adding -g to the above output makes the output even more useful | ||
807 | e.g. typing | ||
808 | make CC:="s390-gcc -g" kernel/sched.s | ||
809 | |||
810 | which compiles. | ||
811 | s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -S kernel/sched.c -o kernel/sched.s | ||
812 | |||
813 | also outputs stabs ( debugger ) info, from this info you can find out the | ||
814 | offsets & sizes of various elements in structures. | ||
815 | e.g. the stab for the structure | ||
816 | struct rlimit { | ||
817 | unsigned long rlim_cur; | ||
818 | unsigned long rlim_max; | ||
819 | }; | ||
820 | is | ||
821 | .stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0 | ||
822 | from this stab you can see that | ||
823 | rlimit_cur starts at bit offset 0 & is 32 bits in size | ||
824 | rlimit_max starts at bit offset 32 & is 32 bits in size. | ||
825 | |||
826 | |||
827 | Debugging Tools: | ||
828 | ================ | ||
829 | |||
830 | objdump | ||
831 | ======= | ||
832 | This is a tool with many options the most useful being ( if compiled with -g). | ||
833 | objdump --source <victim program or object file> > <victims debug listing > | ||
834 | |||
835 | |||
836 | The whole kernel can be compiled like this ( Doing this will make a 17MB kernel | ||
837 | & a 200 MB listing ) however you have to strip it before building the image | ||
838 | using the strip command to make it a more reasonable size to boot it. | ||
839 | |||
840 | A source/assembly mixed dump of the kernel can be done with the line | ||
841 | objdump --source vmlinux > vmlinux.lst | ||
842 | Also, if the file isn't compiled -g, this will output as much debugging information | ||
843 | as it can (e.g. function names). This is very slow as it spends lots | ||
844 | of time searching for debugging info. The following self explanatory line should be used | ||
845 | instead if the code isn't compiled -g, as it is much faster: | ||
846 | objdump --disassemble-all --syms vmlinux > vmlinux.lst | ||
847 | |||
848 | As hard drive space is valuable most of us use the following approach. | ||
849 | 1) Look at the emitted psw on the console to find the crash address in the kernel. | ||
850 | 2) Look at the file System.map ( in the linux directory ) produced when building | ||
851 | the kernel to find the closest address less than the current PSW to find the | ||
852 | offending function. | ||
853 | 3) use grep or similar to search the source tree looking for the source file | ||
854 | with this function if you don't know where it is. | ||
855 | 4) rebuild this object file with -g on, as an example suppose the file was | ||
856 | ( /arch/s390/kernel/signal.o ) | ||
857 | 5) Assuming the file with the erroneous function is signal.c Move to the base of the | ||
858 | Linux source tree. | ||
859 | 6) rm /arch/s390/kernel/signal.o | ||
860 | 7) make /arch/s390/kernel/signal.o | ||
861 | 8) watch the gcc command line emitted | ||
862 | 9) type it in again or alternatively cut & paste it on the console adding the -g option. | ||
863 | 10) objdump --source arch/s390/kernel/signal.o > signal.lst | ||
864 | This will output the source & the assembly intermixed, as the snippet below shows | ||
865 | This will unfortunately output addresses which aren't the same | ||
866 | as the kernel ones you should be able to get around the mental arithmetic | ||
867 | by playing with the --adjust-vma parameter to objdump. | ||
868 | |||
869 | |||
870 | |||
871 | |||
872 | static inline void spin_lock(spinlock_t *lp) | ||
873 | { | ||
874 | a0: 18 34 lr %r3,%r4 | ||
875 | a2: a7 3a 03 bc ahi %r3,956 | ||
876 | __asm__ __volatile(" lhi 1,-1\n" | ||
877 | a6: a7 18 ff ff lhi %r1,-1 | ||
878 | aa: 1f 00 slr %r0,%r0 | ||
879 | ac: ba 01 30 00 cs %r0,%r1,0(%r3) | ||
880 | b0: a7 44 ff fd jm aa <sys_sigsuspend+0x2e> | ||
881 | saveset = current->blocked; | ||
882 | b4: d2 07 f0 68 mvc 104(8,%r15),972(%r4) | ||
883 | b8: 43 cc | ||
884 | return (set->sig[0] & mask) != 0; | ||
885 | } | ||
886 | |||
887 | 6) If debugging under VM go down to that section in the document for more info. | ||
888 | |||
889 | |||
890 | I now have a tool which takes the pain out of --adjust-vma | ||
891 | & you are able to do something like | ||
892 | make /arch/s390/kernel/traps.lst | ||
893 | & it automatically generates the correctly relocated entries for | ||
894 | the text segment in traps.lst. | ||
895 | This tool is now standard in linux distro's in scripts/makelst | ||
896 | |||
897 | strace: | ||
898 | ------- | ||
899 | Q. What is it ? | ||
900 | A. It is a tool for intercepting calls to the kernel & logging them | ||
901 | to a file & on the screen. | ||
902 | |||
903 | Q. What use is it ? | ||
904 | A. You can use it to find out what files a particular program opens. | ||
905 | |||
906 | |||
907 | 738 | ||
908 | Example 1 | ||
909 | --------- | ||
910 | If you wanted to know does ping work but didn't have the source | ||
911 | strace ping -c 1 127.0.0.1 | ||
912 | & then look at the man pages for each of the syscalls below, | ||
913 | ( In fact this is sometimes easier than looking at some spaghetti | ||
914 | source which conditionally compiles for several architectures ). | ||
915 | Not everything that it throws out needs to make sense immediately. | ||
916 | |||
917 | Just looking quickly you can see that it is making up a RAW socket | ||
918 | for the ICMP protocol. | ||
919 | Doing an alarm(10) for a 10 second timeout | ||
920 | & doing a gettimeofday call before & after each read to see | ||
921 | how long the replies took, & writing some text to stdout so the user | ||
922 | has an idea what is going on. | ||
923 | |||
924 | socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3 | ||
925 | getuid() = 0 | ||
926 | setuid(0) = 0 | ||
927 | stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) | ||
928 | stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory) | ||
929 | stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory) | ||
930 | getpid() = 353 | ||
931 | setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 | ||
932 | setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0 | ||
933 | fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0 | ||
934 | mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000 | ||
935 | ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0 | ||
936 | write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes | ||
937 | ) = 42 | ||
938 | sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0 | ||
939 | sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0 | ||
940 | gettimeofday({948904719, 138951}, NULL) = 0 | ||
941 | sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET, | ||
942 | sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64 | ||
943 | sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 | ||
944 | sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0 | ||
945 | alarm(10) = 0 | ||
946 | recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0, | ||
947 | {sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 | ||
948 | gettimeofday({948904719, 160224}, NULL) = 0 | ||
949 | recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0, | ||
950 | {sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84 | ||
951 | gettimeofday({948904719, 166952}, NULL) = 0 | ||
952 | write(1, "64 bytes from 127.0.0.1: icmp_se"..., | ||
953 | 5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms | ||
954 | |||
955 | Example 2 | ||
956 | --------- | ||
957 | strace passwd 2>&1 | grep open | ||
958 | produces the following output | ||
959 | open("/etc/ld.so.cache", O_RDONLY) = 3 | ||
960 | open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory) | ||
961 | open("/lib/libc.so.5", O_RDONLY) = 3 | ||
962 | open("/dev", O_RDONLY) = 3 | ||
963 | open("/var/run/utmp", O_RDONLY) = 3 | ||
964 | open("/etc/passwd", O_RDONLY) = 3 | ||
965 | open("/etc/shadow", O_RDONLY) = 3 | ||
966 | open("/etc/login.defs", O_RDONLY) = 4 | ||
967 | open("/dev/tty", O_RDONLY) = 4 | ||
968 | |||
969 | The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input | ||
970 | through the pipe for each line containing the string open. | ||
971 | |||
972 | |||
973 | Example 3 | ||
974 | --------- | ||
975 | Getting sophisticated | ||
976 | telnetd crashes & I don't know why | ||
977 | |||
978 | Steps | ||
979 | ----- | ||
980 | 1) Replace the following line in /etc/inetd.conf | ||
981 | telnet stream tcp nowait root /usr/sbin/in.telnetd -h | ||
982 | with | ||
983 | telnet stream tcp nowait root /blah | ||
984 | |||
985 | 2) Create the file /blah with the following contents to start tracing telnetd | ||
986 | #!/bin/bash | ||
987 | /usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h | ||
988 | 3) chmod 700 /blah to make it executable only to root | ||
989 | 4) | ||
990 | killall -HUP inetd | ||
991 | or ps aux | grep inetd | ||
992 | get inetd's process id | ||
993 | & kill -HUP inetd to restart it. | ||
994 | |||
995 | Important options | ||
996 | ----------------- | ||
997 | -o is used to tell strace to output to a file in our case t1 in the root directory | ||
998 | -f is to follow children i.e. | ||
999 | e.g in our case above telnetd will start the login process & subsequently a shell like bash. | ||
1000 | You will be able to tell which is which from the process ID's listed on the left hand side | ||
1001 | of the strace output. | ||
1002 | -p<pid> will tell strace to attach to a running process, yup this can be done provided | ||
1003 | it isn't being traced or debugged already & you have enough privileges, | ||
1004 | the reason 2 processes cannot trace or debug the same program is that strace | ||
1005 | becomes the parent process of the one being debugged & processes ( unlike people ) | ||
1006 | can have only one parent. | ||
1007 | |||
1008 | |||
1009 | However the file /t1 will get big quite quickly | ||
1010 | to test it telnet 127.0.0.1 | ||
1011 | |||
1012 | now look at what files in.telnetd execve'd | ||
1013 | 413 execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0 | ||
1014 | 414 execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0 | ||
1015 | |||
1016 | Whey it worked!. | ||
1017 | |||
1018 | |||
1019 | Other hints: | ||
1020 | ------------ | ||
1021 | If the program is not very interactive ( i.e. not much keyboard input ) | ||
1022 | & is crashing in one architecture but not in another you can do | ||
1023 | an strace of both programs under as identical a scenario as you can | ||
1024 | on both architectures outputting to a file then. | ||
1025 | do a diff of the two traces using the diff program | ||
1026 | i.e. | ||
1027 | diff output1 output2 | ||
1028 | & maybe you'll be able to see where the call paths differed, this | ||
1029 | is possibly near the cause of the crash. | ||
1030 | |||
1031 | More info | ||
1032 | --------- | ||
1033 | Look at man pages for strace & the various syscalls | ||
1034 | e.g. man strace, man alarm, man socket. | ||
1035 | |||
1036 | |||
1037 | Performance Debugging | ||
1038 | ===================== | ||
1039 | gcc is capable of compiling in profiling code just add the -p option | ||
1040 | to the CFLAGS, this obviously affects program size & performance. | ||
1041 | This can be used by the gprof gnu profiling tool or the | ||
1042 | gcov the gnu code coverage tool ( code coverage is a means of testing | ||
1043 | code quality by checking if all the code in an executable in exercised by | ||
1044 | a tester ). | ||
1045 | |||
1046 | |||
1047 | Using top to find out where processes are sleeping in the kernel | ||
1048 | ---------------------------------------------------------------- | ||
1049 | To do this copy the System.map from the root directory where | ||
1050 | the linux kernel was built to the /boot directory on your | ||
1051 | linux machine. | ||
1052 | Start top | ||
1053 | Now type fU<return> | ||
1054 | You should see a new field called WCHAN which | ||
1055 | tells you where each process is sleeping here is a typical output. | ||
1056 | |||
1057 | 6:59pm up 41 min, 1 user, load average: 0.00, 0.00, 0.00 | ||
1058 | 28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped | ||
1059 | CPU states: 0.0% user, 0.1% system, 0.0% nice, 99.8% idle | ||
1060 | Mem: 254900K av, 45976K used, 208924K free, 0K shrd, 28636K buff | ||
1061 | Swap: 0K av, 0K used, 0K free 8620K cached | ||
1062 | |||
1063 | PID USER PRI NI SIZE RSS SHARE WCHAN STAT LIB %CPU %MEM TIME COMMAND | ||
1064 | 750 root 12 0 848 848 700 do_select S 0 0.1 0.3 0:00 in.telnetd | ||
1065 | 767 root 16 0 1140 1140 964 R 0 0.1 0.4 0:00 top | ||
1066 | 1 root 8 0 212 212 180 do_select S 0 0.0 0.0 0:00 init | ||
1067 | 2 root 9 0 0 0 0 down_inte SW 0 0.0 0.0 0:00 kmcheck | ||
1068 | |||
1069 | The time command | ||
1070 | ---------------- | ||
1071 | Another related command is the time command which gives you an indication | ||
1072 | of where a process is spending the majority of its time. | ||
1073 | e.g. | ||
1074 | time ping -c 5 nc | ||
1075 | outputs | ||
1076 | real 0m4.054s | ||
1077 | user 0m0.010s | ||
1078 | sys 0m0.010s | ||
1079 | 739 | ||
1080 | Debugging under VM | 740 | Debugging under VM |
1081 | ================== | 741 | ================== |
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 4236408070e5..6259895fcd97 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h | |||
@@ -11,200 +11,28 @@ | |||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/bug.h> | 12 | #include <linux/bug.h> |
13 | 13 | ||
14 | extern void __xchg_called_with_bad_pointer(void); | 14 | #define cmpxchg(ptr, o, n) \ |
15 | 15 | ({ \ | |
16 | static inline unsigned long __xchg(unsigned long x, void *ptr, int size) | 16 | __typeof__(*(ptr)) __o = (o); \ |
17 | { | 17 | __typeof__(*(ptr)) __n = (n); \ |
18 | unsigned long addr, old; | 18 | (__typeof__(*(ptr))) __sync_val_compare_and_swap((ptr),__o,__n);\ |
19 | int shift; | ||
20 | |||
21 | switch (size) { | ||
22 | case 1: | ||
23 | addr = (unsigned long) ptr; | ||
24 | shift = (3 ^ (addr & 3)) << 3; | ||
25 | addr ^= addr & 3; | ||
26 | asm volatile( | ||
27 | " l %0,%4\n" | ||
28 | "0: lr 0,%0\n" | ||
29 | " nr 0,%3\n" | ||
30 | " or 0,%2\n" | ||
31 | " cs %0,0,%4\n" | ||
32 | " jl 0b\n" | ||
33 | : "=&d" (old), "=Q" (*(int *) addr) | ||
34 | : "d" ((x & 0xff) << shift), "d" (~(0xff << shift)), | ||
35 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
36 | return old >> shift; | ||
37 | case 2: | ||
38 | addr = (unsigned long) ptr; | ||
39 | shift = (2 ^ (addr & 2)) << 3; | ||
40 | addr ^= addr & 2; | ||
41 | asm volatile( | ||
42 | " l %0,%4\n" | ||
43 | "0: lr 0,%0\n" | ||
44 | " nr 0,%3\n" | ||
45 | " or 0,%2\n" | ||
46 | " cs %0,0,%4\n" | ||
47 | " jl 0b\n" | ||
48 | : "=&d" (old), "=Q" (*(int *) addr) | ||
49 | : "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift)), | ||
50 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
51 | return old >> shift; | ||
52 | case 4: | ||
53 | asm volatile( | ||
54 | " l %0,%3\n" | ||
55 | "0: cs %0,%2,%3\n" | ||
56 | " jl 0b\n" | ||
57 | : "=&d" (old), "=Q" (*(int *) ptr) | ||
58 | : "d" (x), "Q" (*(int *) ptr) | ||
59 | : "memory", "cc"); | ||
60 | return old; | ||
61 | #ifdef CONFIG_64BIT | ||
62 | case 8: | ||
63 | asm volatile( | ||
64 | " lg %0,%3\n" | ||
65 | "0: csg %0,%2,%3\n" | ||
66 | " jl 0b\n" | ||
67 | : "=&d" (old), "=m" (*(long *) ptr) | ||
68 | : "d" (x), "Q" (*(long *) ptr) | ||
69 | : "memory", "cc"); | ||
70 | return old; | ||
71 | #endif /* CONFIG_64BIT */ | ||
72 | } | ||
73 | __xchg_called_with_bad_pointer(); | ||
74 | return x; | ||
75 | } | ||
76 | |||
77 | #define xchg(ptr, x) \ | ||
78 | ({ \ | ||
79 | __typeof__(*(ptr)) __ret; \ | ||
80 | __ret = (__typeof__(*(ptr))) \ | ||
81 | __xchg((unsigned long)(x), (void *)(ptr), sizeof(*(ptr)));\ | ||
82 | __ret; \ | ||
83 | }) | 19 | }) |
84 | 20 | ||
85 | /* | 21 | #define cmpxchg64 cmpxchg |
86 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | 22 | #define cmpxchg_local cmpxchg |
87 | * store NEW in MEM. Return the initial value in MEM. Success is | 23 | #define cmpxchg64_local cmpxchg |
88 | * indicated by comparing RETURN with OLD. | ||
89 | */ | ||
90 | |||
91 | #define __HAVE_ARCH_CMPXCHG | ||
92 | |||
93 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
94 | |||
95 | static inline unsigned long __cmpxchg(void *ptr, unsigned long old, | ||
96 | unsigned long new, int size) | ||
97 | { | ||
98 | unsigned long addr, prev, tmp; | ||
99 | int shift; | ||
100 | |||
101 | switch (size) { | ||
102 | case 1: | ||
103 | addr = (unsigned long) ptr; | ||
104 | shift = (3 ^ (addr & 3)) << 3; | ||
105 | addr ^= addr & 3; | ||
106 | asm volatile( | ||
107 | " l %0,%2\n" | ||
108 | "0: nr %0,%5\n" | ||
109 | " lr %1,%0\n" | ||
110 | " or %0,%3\n" | ||
111 | " or %1,%4\n" | ||
112 | " cs %0,%1,%2\n" | ||
113 | " jnl 1f\n" | ||
114 | " xr %1,%0\n" | ||
115 | " nr %1,%5\n" | ||
116 | " jnz 0b\n" | ||
117 | "1:" | ||
118 | : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) | ||
119 | : "d" ((old & 0xff) << shift), | ||
120 | "d" ((new & 0xff) << shift), | ||
121 | "d" (~(0xff << shift)) | ||
122 | : "memory", "cc"); | ||
123 | return prev >> shift; | ||
124 | case 2: | ||
125 | addr = (unsigned long) ptr; | ||
126 | shift = (2 ^ (addr & 2)) << 3; | ||
127 | addr ^= addr & 2; | ||
128 | asm volatile( | ||
129 | " l %0,%2\n" | ||
130 | "0: nr %0,%5\n" | ||
131 | " lr %1,%0\n" | ||
132 | " or %0,%3\n" | ||
133 | " or %1,%4\n" | ||
134 | " cs %0,%1,%2\n" | ||
135 | " jnl 1f\n" | ||
136 | " xr %1,%0\n" | ||
137 | " nr %1,%5\n" | ||
138 | " jnz 0b\n" | ||
139 | "1:" | ||
140 | : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) | ||
141 | : "d" ((old & 0xffff) << shift), | ||
142 | "d" ((new & 0xffff) << shift), | ||
143 | "d" (~(0xffff << shift)) | ||
144 | : "memory", "cc"); | ||
145 | return prev >> shift; | ||
146 | case 4: | ||
147 | asm volatile( | ||
148 | " cs %0,%3,%1\n" | ||
149 | : "=&d" (prev), "=Q" (*(int *) ptr) | ||
150 | : "0" (old), "d" (new), "Q" (*(int *) ptr) | ||
151 | : "memory", "cc"); | ||
152 | return prev; | ||
153 | #ifdef CONFIG_64BIT | ||
154 | case 8: | ||
155 | asm volatile( | ||
156 | " csg %0,%3,%1\n" | ||
157 | : "=&d" (prev), "=Q" (*(long *) ptr) | ||
158 | : "0" (old), "d" (new), "Q" (*(long *) ptr) | ||
159 | : "memory", "cc"); | ||
160 | return prev; | ||
161 | #endif /* CONFIG_64BIT */ | ||
162 | } | ||
163 | __cmpxchg_called_with_bad_pointer(); | ||
164 | return old; | ||
165 | } | ||
166 | |||
167 | #define cmpxchg(ptr, o, n) \ | ||
168 | ({ \ | ||
169 | __typeof__(*(ptr)) __ret; \ | ||
170 | __ret = (__typeof__(*(ptr))) \ | ||
171 | __cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), \ | ||
172 | sizeof(*(ptr))); \ | ||
173 | __ret; \ | ||
174 | }) | ||
175 | 24 | ||
176 | #ifdef CONFIG_64BIT | 25 | #define xchg(ptr, x) \ |
177 | #define cmpxchg64(ptr, o, n) \ | ||
178 | ({ \ | 26 | ({ \ |
179 | cmpxchg((ptr), (o), (n)); \ | 27 | __typeof__(ptr) __ptr = (ptr); \ |
28 | __typeof__(*(ptr)) __old; \ | ||
29 | do { \ | ||
30 | __old = *__ptr; \ | ||
31 | } while (!__sync_bool_compare_and_swap(__ptr, __old, x)); \ | ||
32 | __old; \ | ||
180 | }) | 33 | }) |
181 | #else /* CONFIG_64BIT */ | ||
182 | static inline unsigned long long __cmpxchg64(void *ptr, | ||
183 | unsigned long long old, | ||
184 | unsigned long long new) | ||
185 | { | ||
186 | register_pair rp_old = {.pair = old}; | ||
187 | register_pair rp_new = {.pair = new}; | ||
188 | unsigned long long *ullptr = ptr; | ||
189 | 34 | ||
190 | asm volatile( | 35 | #define __HAVE_ARCH_CMPXCHG |
191 | " cds %0,%2,%1" | ||
192 | : "+d" (rp_old), "+Q" (*ullptr) | ||
193 | : "d" (rp_new) | ||
194 | : "memory", "cc"); | ||
195 | return rp_old.pair; | ||
196 | } | ||
197 | |||
198 | #define cmpxchg64(ptr, o, n) \ | ||
199 | ({ \ | ||
200 | __typeof__(*(ptr)) __ret; \ | ||
201 | __ret = (__typeof__(*(ptr))) \ | ||
202 | __cmpxchg64((ptr), \ | ||
203 | (unsigned long long)(o), \ | ||
204 | (unsigned long long)(n)); \ | ||
205 | __ret; \ | ||
206 | }) | ||
207 | #endif /* CONFIG_64BIT */ | ||
208 | 36 | ||
209 | #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \ | 37 | #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \ |
210 | ({ \ | 38 | ({ \ |
@@ -265,40 +93,4 @@ extern void __cmpxchg_double_called_with_bad_pointer(void); | |||
265 | 93 | ||
266 | #define system_has_cmpxchg_double() 1 | 94 | #define system_has_cmpxchg_double() 1 |
267 | 95 | ||
268 | #include <asm-generic/cmpxchg-local.h> | ||
269 | |||
270 | static inline unsigned long __cmpxchg_local(void *ptr, | ||
271 | unsigned long old, | ||
272 | unsigned long new, int size) | ||
273 | { | ||
274 | switch (size) { | ||
275 | case 1: | ||
276 | case 2: | ||
277 | case 4: | ||
278 | #ifdef CONFIG_64BIT | ||
279 | case 8: | ||
280 | #endif | ||
281 | return __cmpxchg(ptr, old, new, size); | ||
282 | default: | ||
283 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
284 | } | ||
285 | |||
286 | return old; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
291 | * them available. | ||
292 | */ | ||
293 | #define cmpxchg_local(ptr, o, n) \ | ||
294 | ({ \ | ||
295 | __typeof__(*(ptr)) __ret; \ | ||
296 | __ret = (__typeof__(*(ptr))) \ | ||
297 | __cmpxchg_local((ptr), (unsigned long)(o), \ | ||
298 | (unsigned long)(n), sizeof(*(ptr))); \ | ||
299 | __ret; \ | ||
300 | }) | ||
301 | |||
302 | #define cmpxchg64_local(ptr, o, n) cmpxchg64((ptr), (o), (n)) | ||
303 | |||
304 | #endif /* __ASM_CMPXCHG_H */ | 96 | #endif /* __ASM_CMPXCHG_H */ |
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index f8c196984853..b91e960e4045 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <asm/div64.h> | 11 | #include <asm/div64.h> |
12 | 12 | ||
13 | #define CPUTIME_PER_USEC 4096ULL | ||
14 | #define CPUTIME_PER_SEC (CPUTIME_PER_USEC * USEC_PER_SEC) | ||
13 | 15 | ||
14 | /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */ | 16 | /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */ |
15 | 17 | ||
@@ -38,24 +40,24 @@ static inline unsigned long __div(unsigned long long n, unsigned long base) | |||
38 | */ | 40 | */ |
39 | static inline unsigned long cputime_to_jiffies(const cputime_t cputime) | 41 | static inline unsigned long cputime_to_jiffies(const cputime_t cputime) |
40 | { | 42 | { |
41 | return __div((__force unsigned long long) cputime, 4096000000ULL / HZ); | 43 | return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / HZ); |
42 | } | 44 | } |
43 | 45 | ||
44 | static inline cputime_t jiffies_to_cputime(const unsigned int jif) | 46 | static inline cputime_t jiffies_to_cputime(const unsigned int jif) |
45 | { | 47 | { |
46 | return (__force cputime_t)(jif * (4096000000ULL / HZ)); | 48 | return (__force cputime_t)(jif * (CPUTIME_PER_SEC / HZ)); |
47 | } | 49 | } |
48 | 50 | ||
49 | static inline u64 cputime64_to_jiffies64(cputime64_t cputime) | 51 | static inline u64 cputime64_to_jiffies64(cputime64_t cputime) |
50 | { | 52 | { |
51 | unsigned long long jif = (__force unsigned long long) cputime; | 53 | unsigned long long jif = (__force unsigned long long) cputime; |
52 | do_div(jif, 4096000000ULL / HZ); | 54 | do_div(jif, CPUTIME_PER_SEC / HZ); |
53 | return jif; | 55 | return jif; |
54 | } | 56 | } |
55 | 57 | ||
56 | static inline cputime64_t jiffies64_to_cputime64(const u64 jif) | 58 | static inline cputime64_t jiffies64_to_cputime64(const u64 jif) |
57 | { | 59 | { |
58 | return (__force cputime64_t)(jif * (4096000000ULL / HZ)); | 60 | return (__force cputime64_t)(jif * (CPUTIME_PER_SEC / HZ)); |
59 | } | 61 | } |
60 | 62 | ||
61 | /* | 63 | /* |
@@ -68,7 +70,7 @@ static inline unsigned int cputime_to_usecs(const cputime_t cputime) | |||
68 | 70 | ||
69 | static inline cputime_t usecs_to_cputime(const unsigned int m) | 71 | static inline cputime_t usecs_to_cputime(const unsigned int m) |
70 | { | 72 | { |
71 | return (__force cputime_t)(m * 4096ULL); | 73 | return (__force cputime_t)(m * CPUTIME_PER_USEC); |
72 | } | 74 | } |
73 | 75 | ||
74 | #define usecs_to_cputime64(m) usecs_to_cputime(m) | 76 | #define usecs_to_cputime64(m) usecs_to_cputime(m) |
@@ -78,12 +80,12 @@ static inline cputime_t usecs_to_cputime(const unsigned int m) | |||
78 | */ | 80 | */ |
79 | static inline unsigned int cputime_to_secs(const cputime_t cputime) | 81 | static inline unsigned int cputime_to_secs(const cputime_t cputime) |
80 | { | 82 | { |
81 | return __div((__force unsigned long long) cputime, 2048000000) >> 1; | 83 | return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / 2) >> 1; |
82 | } | 84 | } |
83 | 85 | ||
84 | static inline cputime_t secs_to_cputime(const unsigned int s) | 86 | static inline cputime_t secs_to_cputime(const unsigned int s) |
85 | { | 87 | { |
86 | return (__force cputime_t)(s * 4096000000ULL); | 88 | return (__force cputime_t)(s * CPUTIME_PER_SEC); |
87 | } | 89 | } |
88 | 90 | ||
89 | /* | 91 | /* |
@@ -91,8 +93,8 @@ static inline cputime_t secs_to_cputime(const unsigned int s) | |||
91 | */ | 93 | */ |
92 | static inline cputime_t timespec_to_cputime(const struct timespec *value) | 94 | static inline cputime_t timespec_to_cputime(const struct timespec *value) |
93 | { | 95 | { |
94 | unsigned long long ret = value->tv_sec * 4096000000ULL; | 96 | unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC; |
95 | return (__force cputime_t)(ret + value->tv_nsec * 4096 / 1000); | 97 | return (__force cputime_t)(ret + __div(value->tv_nsec * CPUTIME_PER_USEC, NSEC_PER_USEC)); |
96 | } | 98 | } |
97 | 99 | ||
98 | static inline void cputime_to_timespec(const cputime_t cputime, | 100 | static inline void cputime_to_timespec(const cputime_t cputime, |
@@ -103,12 +105,12 @@ static inline void cputime_to_timespec(const cputime_t cputime, | |||
103 | register_pair rp; | 105 | register_pair rp; |
104 | 106 | ||
105 | rp.pair = __cputime >> 1; | 107 | rp.pair = __cputime >> 1; |
106 | asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL)); | 108 | asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_SEC / 2)); |
107 | value->tv_nsec = rp.subreg.even * 1000 / 4096; | 109 | value->tv_nsec = rp.subreg.even * NSEC_PER_USEC / CPUTIME_PER_USEC; |
108 | value->tv_sec = rp.subreg.odd; | 110 | value->tv_sec = rp.subreg.odd; |
109 | #else | 111 | #else |
110 | value->tv_nsec = (__cputime % 4096000000ULL) * 1000 / 4096; | 112 | value->tv_nsec = (__cputime % CPUTIME_PER_SEC) * NSEC_PER_USEC / CPUTIME_PER_USEC; |
111 | value->tv_sec = __cputime / 4096000000ULL; | 113 | value->tv_sec = __cputime / CPUTIME_PER_SEC; |
112 | #endif | 114 | #endif |
113 | } | 115 | } |
114 | 116 | ||
@@ -119,8 +121,8 @@ static inline void cputime_to_timespec(const cputime_t cputime, | |||
119 | */ | 121 | */ |
120 | static inline cputime_t timeval_to_cputime(const struct timeval *value) | 122 | static inline cputime_t timeval_to_cputime(const struct timeval *value) |
121 | { | 123 | { |
122 | unsigned long long ret = value->tv_sec * 4096000000ULL; | 124 | unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC; |
123 | return (__force cputime_t)(ret + value->tv_usec * 4096ULL); | 125 | return (__force cputime_t)(ret + value->tv_usec * CPUTIME_PER_USEC); |
124 | } | 126 | } |
125 | 127 | ||
126 | static inline void cputime_to_timeval(const cputime_t cputime, | 128 | static inline void cputime_to_timeval(const cputime_t cputime, |
@@ -131,12 +133,12 @@ static inline void cputime_to_timeval(const cputime_t cputime, | |||
131 | register_pair rp; | 133 | register_pair rp; |
132 | 134 | ||
133 | rp.pair = __cputime >> 1; | 135 | rp.pair = __cputime >> 1; |
134 | asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL)); | 136 | asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_USEC / 2)); |
135 | value->tv_usec = rp.subreg.even / 4096; | 137 | value->tv_usec = rp.subreg.even / CPUTIME_PER_USEC; |
136 | value->tv_sec = rp.subreg.odd; | 138 | value->tv_sec = rp.subreg.odd; |
137 | #else | 139 | #else |
138 | value->tv_usec = (__cputime % 4096000000ULL) / 4096; | 140 | value->tv_usec = (__cputime % CPUTIME_PER_SEC) / CPUTIME_PER_USEC; |
139 | value->tv_sec = __cputime / 4096000000ULL; | 141 | value->tv_sec = __cputime / CPUTIME_PER_SEC; |
140 | #endif | 142 | #endif |
141 | } | 143 | } |
142 | 144 | ||
@@ -146,13 +148,13 @@ static inline void cputime_to_timeval(const cputime_t cputime, | |||
146 | static inline clock_t cputime_to_clock_t(cputime_t cputime) | 148 | static inline clock_t cputime_to_clock_t(cputime_t cputime) |
147 | { | 149 | { |
148 | unsigned long long clock = (__force unsigned long long) cputime; | 150 | unsigned long long clock = (__force unsigned long long) cputime; |
149 | do_div(clock, 4096000000ULL / USER_HZ); | 151 | do_div(clock, CPUTIME_PER_SEC / USER_HZ); |
150 | return clock; | 152 | return clock; |
151 | } | 153 | } |
152 | 154 | ||
153 | static inline cputime_t clock_t_to_cputime(unsigned long x) | 155 | static inline cputime_t clock_t_to_cputime(unsigned long x) |
154 | { | 156 | { |
155 | return (__force cputime_t)(x * (4096000000ULL / USER_HZ)); | 157 | return (__force cputime_t)(x * (CPUTIME_PER_SEC / USER_HZ)); |
156 | } | 158 | } |
157 | 159 | ||
158 | /* | 160 | /* |
@@ -161,7 +163,7 @@ static inline cputime_t clock_t_to_cputime(unsigned long x) | |||
161 | static inline clock_t cputime64_to_clock_t(cputime64_t cputime) | 163 | static inline clock_t cputime64_to_clock_t(cputime64_t cputime) |
162 | { | 164 | { |
163 | unsigned long long clock = (__force unsigned long long) cputime; | 165 | unsigned long long clock = (__force unsigned long long) cputime; |
164 | do_div(clock, 4096000000ULL / USER_HZ); | 166 | do_div(clock, CPUTIME_PER_SEC / USER_HZ); |
165 | return clock; | 167 | return clock; |
166 | } | 168 | } |
167 | 169 | ||
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index 530c15eb01e9..0206c8052328 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h | |||
@@ -151,9 +151,21 @@ debug_text_event(debug_info_t* id, int level, const char* txt) | |||
151 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! | 151 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! |
152 | */ | 152 | */ |
153 | extern debug_entry_t * | 153 | extern debug_entry_t * |
154 | debug_sprintf_event(debug_info_t* id,int level,char *string,...) | 154 | __debug_sprintf_event(debug_info_t *id, int level, char *string, ...) |
155 | __attribute__ ((format(printf, 3, 4))); | 155 | __attribute__ ((format(printf, 3, 4))); |
156 | 156 | ||
157 | #define debug_sprintf_event(_id, _level, _fmt, ...) \ | ||
158 | ({ \ | ||
159 | debug_entry_t *__ret; \ | ||
160 | debug_info_t *__id = _id; \ | ||
161 | int __level = _level; \ | ||
162 | if ((!__id) || (__level > __id->level)) \ | ||
163 | __ret = NULL; \ | ||
164 | else \ | ||
165 | __ret = __debug_sprintf_event(__id, __level, \ | ||
166 | _fmt, ## __VA_ARGS__); \ | ||
167 | __ret; \ | ||
168 | }) | ||
157 | 169 | ||
158 | static inline debug_entry_t* | 170 | static inline debug_entry_t* |
159 | debug_exception(debug_info_t* id, int level, void* data, int length) | 171 | debug_exception(debug_info_t* id, int level, void* data, int length) |
@@ -194,9 +206,22 @@ debug_text_exception(debug_info_t* id, int level, const char* txt) | |||
194 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! | 206 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! |
195 | */ | 207 | */ |
196 | extern debug_entry_t * | 208 | extern debug_entry_t * |
197 | debug_sprintf_exception(debug_info_t* id,int level,char *string,...) | 209 | __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...) |
198 | __attribute__ ((format(printf, 3, 4))); | 210 | __attribute__ ((format(printf, 3, 4))); |
199 | 211 | ||
212 | #define debug_sprintf_exception(_id, _level, _fmt, ...) \ | ||
213 | ({ \ | ||
214 | debug_entry_t *__ret; \ | ||
215 | debug_info_t *__id = _id; \ | ||
216 | int __level = _level; \ | ||
217 | if ((!__id) || (__level > __id->level)) \ | ||
218 | __ret = NULL; \ | ||
219 | else \ | ||
220 | __ret = __debug_sprintf_exception(__id, __level, \ | ||
221 | _fmt, ## __VA_ARGS__);\ | ||
222 | __ret; \ | ||
223 | }) | ||
224 | |||
200 | int debug_register_view(debug_info_t* id, struct debug_view* view); | 225 | int debug_register_view(debug_info_t* id, struct debug_view* view); |
201 | int debug_unregister_view(debug_info_t* id, struct debug_view* view); | 226 | int debug_unregister_view(debug_info_t* id, struct debug_view* view); |
202 | 227 | ||
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 3aef8afec336..abb618f1ead2 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h | |||
@@ -1,25 +1,69 @@ | |||
1 | #ifndef _ASM_S390_FTRACE_H | 1 | #ifndef _ASM_S390_FTRACE_H |
2 | #define _ASM_S390_FTRACE_H | 2 | #define _ASM_S390_FTRACE_H |
3 | 3 | ||
4 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | ||
5 | |||
6 | #define MCOUNT_INSN_SIZE 24 | ||
7 | #define MCOUNT_RETURN_FIXUP 18 | ||
8 | |||
4 | #ifndef __ASSEMBLY__ | 9 | #ifndef __ASSEMBLY__ |
5 | 10 | ||
6 | extern void _mcount(void); | 11 | #define ftrace_return_address(n) __builtin_return_address(n) |
12 | |||
13 | void _mcount(void); | ||
14 | void ftrace_caller(void); | ||
15 | |||
7 | extern char ftrace_graph_caller_end; | 16 | extern char ftrace_graph_caller_end; |
17 | extern unsigned long ftrace_plt; | ||
8 | 18 | ||
9 | struct dyn_arch_ftrace { }; | 19 | struct dyn_arch_ftrace { }; |
10 | 20 | ||
11 | #define MCOUNT_ADDR ((long)_mcount) | 21 | #define MCOUNT_ADDR ((unsigned long)_mcount) |
22 | #define FTRACE_ADDR ((unsigned long)ftrace_caller) | ||
12 | 23 | ||
24 | #define KPROBE_ON_FTRACE_NOP 0 | ||
25 | #define KPROBE_ON_FTRACE_CALL 1 | ||
13 | 26 | ||
14 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | 27 | static inline unsigned long ftrace_call_adjust(unsigned long addr) |
15 | { | 28 | { |
16 | return addr; | 29 | return addr; |
17 | } | 30 | } |
18 | 31 | ||
19 | #endif /* __ASSEMBLY__ */ | 32 | struct ftrace_insn { |
33 | u16 opc; | ||
34 | s32 disp; | ||
35 | } __packed; | ||
36 | |||
37 | static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn) | ||
38 | { | ||
39 | #ifdef CONFIG_FUNCTION_TRACER | ||
40 | /* jg .+24 */ | ||
41 | insn->opc = 0xc0f4; | ||
42 | insn->disp = MCOUNT_INSN_SIZE / 2; | ||
43 | #endif | ||
44 | } | ||
20 | 45 | ||
21 | #define MCOUNT_INSN_SIZE 18 | 46 | static inline int is_ftrace_nop(struct ftrace_insn *insn) |
47 | { | ||
48 | #ifdef CONFIG_FUNCTION_TRACER | ||
49 | if (insn->disp == MCOUNT_INSN_SIZE / 2) | ||
50 | return 1; | ||
51 | #endif | ||
52 | return 0; | ||
53 | } | ||
22 | 54 | ||
23 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | 55 | static inline void ftrace_generate_call_insn(struct ftrace_insn *insn, |
56 | unsigned long ip) | ||
57 | { | ||
58 | #ifdef CONFIG_FUNCTION_TRACER | ||
59 | unsigned long target; | ||
60 | |||
61 | /* brasl r0,ftrace_caller */ | ||
62 | target = is_module_addr((void *) ip) ? ftrace_plt : FTRACE_ADDR; | ||
63 | insn->opc = 0xc005; | ||
64 | insn->disp = (target - ip) / 2; | ||
65 | #endif | ||
66 | } | ||
24 | 67 | ||
68 | #endif /* __ASSEMBLY__ */ | ||
25 | #endif /* _ASM_S390_FTRACE_H */ | 69 | #endif /* _ASM_S390_FTRACE_H */ |
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h index 6af037f574b8..113cd963dbbe 100644 --- a/arch/s390/include/asm/idle.h +++ b/arch/s390/include/asm/idle.h | |||
@@ -9,9 +9,10 @@ | |||
9 | 9 | ||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
12 | #include <linux/seqlock.h> | ||
12 | 13 | ||
13 | struct s390_idle_data { | 14 | struct s390_idle_data { |
14 | unsigned int sequence; | 15 | seqcount_t seqcount; |
15 | unsigned long long idle_count; | 16 | unsigned long long idle_count; |
16 | unsigned long long idle_time; | 17 | unsigned long long idle_time; |
17 | unsigned long long clock_idle_enter; | 18 | unsigned long long clock_idle_enter; |
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h index 6ad9013c67e7..30fd5c84680e 100644 --- a/arch/s390/include/asm/io.h +++ b/arch/s390/include/asm/io.h | |||
@@ -39,6 +39,15 @@ static inline void iounmap(volatile void __iomem *addr) | |||
39 | { | 39 | { |
40 | } | 40 | } |
41 | 41 | ||
42 | static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) | ||
43 | { | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static inline void ioport_unmap(void __iomem *p) | ||
48 | { | ||
49 | } | ||
50 | |||
42 | /* | 51 | /* |
43 | * s390 needs a private implementation of pci_iomap since ioremap with its | 52 | * s390 needs a private implementation of pci_iomap since ioremap with its |
44 | * offset parameter isn't sufficient. That's because BAR spaces are not | 53 | * offset parameter isn't sufficient. That's because BAR spaces are not |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index b0d5f0a97a01..343ea7c987aa 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
@@ -1,11 +1,11 @@ | |||
1 | #ifndef _ASM_IRQ_H | 1 | #ifndef _ASM_IRQ_H |
2 | #define _ASM_IRQ_H | 2 | #define _ASM_IRQ_H |
3 | 3 | ||
4 | #define EXT_INTERRUPT 1 | 4 | #define EXT_INTERRUPT 0 |
5 | #define IO_INTERRUPT 2 | 5 | #define IO_INTERRUPT 1 |
6 | #define THIN_INTERRUPT 3 | 6 | #define THIN_INTERRUPT 2 |
7 | 7 | ||
8 | #define NR_IRQS_BASE 4 | 8 | #define NR_IRQS_BASE 3 |
9 | 9 | ||
10 | #ifdef CONFIG_PCI_NR_MSI | 10 | #ifdef CONFIG_PCI_NR_MSI |
11 | # define NR_IRQS (NR_IRQS_BASE + CONFIG_PCI_NR_MSI) | 11 | # define NR_IRQS (NR_IRQS_BASE + CONFIG_PCI_NR_MSI) |
@@ -13,9 +13,6 @@ | |||
13 | # define NR_IRQS NR_IRQS_BASE | 13 | # define NR_IRQS NR_IRQS_BASE |
14 | #endif | 14 | #endif |
15 | 15 | ||
16 | /* This number is used when no interrupt has been assigned */ | ||
17 | #define NO_IRQ 0 | ||
18 | |||
19 | /* External interruption codes */ | 16 | /* External interruption codes */ |
20 | #define EXT_IRQ_INTERRUPT_KEY 0x0040 | 17 | #define EXT_IRQ_INTERRUPT_KEY 0x0040 |
21 | #define EXT_IRQ_CLK_COMP 0x1004 | 18 | #define EXT_IRQ_CLK_COMP 0x1004 |
diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h index 98629173ce3b..b47ad3b642cc 100644 --- a/arch/s390/include/asm/kprobes.h +++ b/arch/s390/include/asm/kprobes.h | |||
@@ -60,6 +60,7 @@ typedef u16 kprobe_opcode_t; | |||
60 | struct arch_specific_insn { | 60 | struct arch_specific_insn { |
61 | /* copy of original instruction */ | 61 | /* copy of original instruction */ |
62 | kprobe_opcode_t *insn; | 62 | kprobe_opcode_t *insn; |
63 | unsigned int is_ftrace_insn : 1; | ||
63 | }; | 64 | }; |
64 | 65 | ||
65 | struct prev_kprobe { | 66 | struct prev_kprobe { |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 6cc51fe84410..34fbcac61133 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -147,7 +147,7 @@ struct _lowcore { | |||
147 | __u32 softirq_pending; /* 0x02ec */ | 147 | __u32 softirq_pending; /* 0x02ec */ |
148 | __u32 percpu_offset; /* 0x02f0 */ | 148 | __u32 percpu_offset; /* 0x02f0 */ |
149 | __u32 machine_flags; /* 0x02f4 */ | 149 | __u32 machine_flags; /* 0x02f4 */ |
150 | __u32 ftrace_func; /* 0x02f8 */ | 150 | __u8 pad_0x02f8[0x02fc-0x02f8]; /* 0x02f8 */ |
151 | __u32 spinlock_lockval; /* 0x02fc */ | 151 | __u32 spinlock_lockval; /* 0x02fc */ |
152 | 152 | ||
153 | __u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */ | 153 | __u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */ |
@@ -297,7 +297,7 @@ struct _lowcore { | |||
297 | __u64 percpu_offset; /* 0x0378 */ | 297 | __u64 percpu_offset; /* 0x0378 */ |
298 | __u64 vdso_per_cpu_data; /* 0x0380 */ | 298 | __u64 vdso_per_cpu_data; /* 0x0380 */ |
299 | __u64 machine_flags; /* 0x0388 */ | 299 | __u64 machine_flags; /* 0x0388 */ |
300 | __u64 ftrace_func; /* 0x0390 */ | 300 | __u8 pad_0x0390[0x0398-0x0390]; /* 0x0390 */ |
301 | __u64 gmap; /* 0x0398 */ | 301 | __u64 gmap; /* 0x0398 */ |
302 | __u32 spinlock_lockval; /* 0x03a0 */ | 302 | __u32 spinlock_lockval; /* 0x03a0 */ |
303 | __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */ | 303 | __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */ |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index c030900320e0..ef803c202d42 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
@@ -50,10 +50,6 @@ struct zpci_fmb { | |||
50 | atomic64_t unmapped_pages; | 50 | atomic64_t unmapped_pages; |
51 | } __packed __aligned(16); | 51 | } __packed __aligned(16); |
52 | 52 | ||
53 | #define ZPCI_MSI_VEC_BITS 11 | ||
54 | #define ZPCI_MSI_VEC_MAX (1 << ZPCI_MSI_VEC_BITS) | ||
55 | #define ZPCI_MSI_VEC_MASK (ZPCI_MSI_VEC_MAX - 1) | ||
56 | |||
57 | enum zpci_state { | 53 | enum zpci_state { |
58 | ZPCI_FN_STATE_RESERVED, | 54 | ZPCI_FN_STATE_RESERVED, |
59 | ZPCI_FN_STATE_STANDBY, | 55 | ZPCI_FN_STATE_STANDBY, |
@@ -90,6 +86,7 @@ struct zpci_dev { | |||
90 | 86 | ||
91 | /* IRQ stuff */ | 87 | /* IRQ stuff */ |
92 | u64 msi_addr; /* MSI address */ | 88 | u64 msi_addr; /* MSI address */ |
89 | unsigned int max_msi; /* maximum number of MSI's */ | ||
93 | struct airq_iv *aibv; /* adapter interrupt bit vector */ | 90 | struct airq_iv *aibv; /* adapter interrupt bit vector */ |
94 | unsigned int aisb; /* number of the summary bit */ | 91 | unsigned int aisb; /* number of the summary bit */ |
95 | 92 | ||
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h index d194d544d694..f664e96f48c7 100644 --- a/arch/s390/include/asm/pci_io.h +++ b/arch/s390/include/asm/pci_io.h | |||
@@ -139,7 +139,8 @@ static inline int zpci_memcpy_fromio(void *dst, | |||
139 | int size, rc = 0; | 139 | int size, rc = 0; |
140 | 140 | ||
141 | while (n > 0) { | 141 | while (n > 0) { |
142 | size = zpci_get_max_write_size((u64) src, (u64) dst, n, 8); | 142 | size = zpci_get_max_write_size((u64 __force) src, |
143 | (u64) dst, n, 8); | ||
143 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | 144 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); |
144 | rc = zpci_read_single(req, dst, offset, size); | 145 | rc = zpci_read_single(req, dst, offset, size); |
145 | if (rc) | 146 | if (rc) |
@@ -162,7 +163,8 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst, | |||
162 | return -EINVAL; | 163 | return -EINVAL; |
163 | 164 | ||
164 | while (n > 0) { | 165 | while (n > 0) { |
165 | size = zpci_get_max_write_size((u64) dst, (u64) src, n, 128); | 166 | size = zpci_get_max_write_size((u64 __force) dst, |
167 | (u64) src, n, 128); | ||
166 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | 168 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); |
167 | 169 | ||
168 | if (size > 8) /* main path */ | 170 | if (size > 8) /* main path */ |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index d39a31c3cdf2..e510b9460efa 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -22,8 +22,6 @@ unsigned long *page_table_alloc(struct mm_struct *); | |||
22 | void page_table_free(struct mm_struct *, unsigned long *); | 22 | void page_table_free(struct mm_struct *, unsigned long *); |
23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); | 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); |
24 | 24 | ||
25 | void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long, | ||
26 | bool init_skey); | ||
27 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 25 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
28 | unsigned long key, bool nq); | 26 | unsigned long key, bool nq); |
29 | 27 | ||
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 57c882761dea..5e102422c9ab 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -133,6 +133,18 @@ extern unsigned long MODULES_END; | |||
133 | #define MODULES_LEN (1UL << 31) | 133 | #define MODULES_LEN (1UL << 31) |
134 | #endif | 134 | #endif |
135 | 135 | ||
136 | static inline int is_module_addr(void *addr) | ||
137 | { | ||
138 | #ifdef CONFIG_64BIT | ||
139 | BUILD_BUG_ON(MODULES_LEN > (1UL << 31)); | ||
140 | if (addr < (void *)MODULES_VADDR) | ||
141 | return 0; | ||
142 | if (addr > (void *)MODULES_END) | ||
143 | return 0; | ||
144 | #endif | ||
145 | return 1; | ||
146 | } | ||
147 | |||
136 | /* | 148 | /* |
137 | * A 31 bit pagetable entry of S390 has following format: | 149 | * A 31 bit pagetable entry of S390 has following format: |
138 | * | PFRA | | OS | | 150 | * | PFRA | | OS | |
@@ -479,6 +491,11 @@ static inline int mm_has_pgste(struct mm_struct *mm) | |||
479 | return 0; | 491 | return 0; |
480 | } | 492 | } |
481 | 493 | ||
494 | /* | ||
495 | * In the case that a guest uses storage keys | ||
496 | * faults should no longer be backed by zero pages | ||
497 | */ | ||
498 | #define mm_forbids_zeropage mm_use_skey | ||
482 | static inline int mm_use_skey(struct mm_struct *mm) | 499 | static inline int mm_use_skey(struct mm_struct *mm) |
483 | { | 500 | { |
484 | #ifdef CONFIG_PGSTE | 501 | #ifdef CONFIG_PGSTE |
@@ -1634,6 +1651,19 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, | |||
1634 | return pmd; | 1651 | return pmd; |
1635 | } | 1652 | } |
1636 | 1653 | ||
1654 | #define __HAVE_ARCH_PMDP_GET_AND_CLEAR_FULL | ||
1655 | static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm, | ||
1656 | unsigned long address, | ||
1657 | pmd_t *pmdp, int full) | ||
1658 | { | ||
1659 | pmd_t pmd = *pmdp; | ||
1660 | |||
1661 | if (!full) | ||
1662 | pmdp_flush_lazy(mm, address, pmdp); | ||
1663 | pmd_clear(pmdp); | ||
1664 | return pmd; | ||
1665 | } | ||
1666 | |||
1637 | #define __HAVE_ARCH_PMDP_CLEAR_FLUSH | 1667 | #define __HAVE_ARCH_PMDP_CLEAR_FLUSH |
1638 | static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma, | 1668 | static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma, |
1639 | unsigned long address, pmd_t *pmdp) | 1669 | unsigned long address, pmd_t *pmdp) |
@@ -1746,7 +1776,8 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) | |||
1746 | extern int vmem_add_mapping(unsigned long start, unsigned long size); | 1776 | extern int vmem_add_mapping(unsigned long start, unsigned long size); |
1747 | extern int vmem_remove_mapping(unsigned long start, unsigned long size); | 1777 | extern int vmem_remove_mapping(unsigned long start, unsigned long size); |
1748 | extern int s390_enable_sie(void); | 1778 | extern int s390_enable_sie(void); |
1749 | extern void s390_enable_skey(void); | 1779 | extern int s390_enable_skey(void); |
1780 | extern void s390_reset_cmma(struct mm_struct *mm); | ||
1750 | 1781 | ||
1751 | /* | 1782 | /* |
1752 | * No page table caches to initialise | 1783 | * No page table caches to initialise |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d559bdb03d18..bed05ea7ec27 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -217,8 +217,6 @@ static inline unsigned short stap(void) | |||
217 | */ | 217 | */ |
218 | static inline void cpu_relax(void) | 218 | static inline void cpu_relax(void) |
219 | { | 219 | { |
220 | if (MACHINE_HAS_DIAG44) | ||
221 | asm volatile("diag 0,0,68"); | ||
222 | barrier(); | 220 | barrier(); |
223 | } | 221 | } |
224 | 222 | ||
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index d6bdf906caa5..0e37cd041241 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h | |||
@@ -18,14 +18,7 @@ extern int spin_retry; | |||
18 | static inline int | 18 | static inline int |
19 | _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new) | 19 | _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new) |
20 | { | 20 | { |
21 | unsigned int old_expected = old; | 21 | return __sync_bool_compare_and_swap(lock, old, new); |
22 | |||
23 | asm volatile( | ||
24 | " cs %0,%3,%1" | ||
25 | : "=d" (old), "=Q" (*lock) | ||
26 | : "0" (old), "d" (new), "Q" (*lock) | ||
27 | : "cc", "memory" ); | ||
28 | return old == old_expected; | ||
29 | } | 22 | } |
30 | 23 | ||
31 | /* | 24 | /* |
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 572c59949004..06d8741ad6f4 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h | |||
@@ -121,6 +121,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, | |||
121 | #ifdef CONFIG_64BIT | 121 | #ifdef CONFIG_64BIT |
122 | if (tlb->mm->context.asce_limit <= (1UL << 31)) | 122 | if (tlb->mm->context.asce_limit <= (1UL << 31)) |
123 | return; | 123 | return; |
124 | pgtable_pmd_page_dtor(virt_to_page(pmd)); | ||
124 | tlb_remove_table(tlb, pmd); | 125 | tlb_remove_table(tlb, pmd); |
125 | #endif | 126 | #endif |
126 | } | 127 | } |
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 4197c89c52d4..2b446cf0cc65 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h | |||
@@ -287,7 +287,9 @@ | |||
287 | #define __NR_getrandom 349 | 287 | #define __NR_getrandom 349 |
288 | #define __NR_memfd_create 350 | 288 | #define __NR_memfd_create 350 |
289 | #define __NR_bpf 351 | 289 | #define __NR_bpf 351 |
290 | #define NR_syscalls 352 | 290 | #define __NR_s390_pci_mmio_write 352 |
291 | #define __NR_s390_pci_mmio_read 353 | ||
292 | #define NR_syscalls 354 | ||
291 | 293 | ||
292 | /* | 294 | /* |
293 | * There are some system calls that are not present on 64 bit, some | 295 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index ef279a136801..e07e91605353 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -17,8 +17,8 @@ | |||
17 | * Make sure that the compiler is new enough. We want a compiler that | 17 | * Make sure that the compiler is new enough. We want a compiler that |
18 | * is known to work with the "Q" assembler constraint. | 18 | * is known to work with the "Q" assembler constraint. |
19 | */ | 19 | */ |
20 | #if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) | 20 | #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) |
21 | #error Your compiler is too old; please use version 3.3.3 or newer | 21 | #error Your compiler is too old; please use version 4.3 or newer |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | int main(void) | 24 | int main(void) |
@@ -156,7 +156,6 @@ int main(void) | |||
156 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 156 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
157 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | 157 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); |
158 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 158 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
159 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); | ||
160 | DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); | 159 | DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); |
161 | BLANK(); | 160 | BLANK(); |
162 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); | 161 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); |
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 009f5eb11125..34d5fa7b01b5 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c | |||
@@ -434,7 +434,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, | |||
434 | ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; | 434 | ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; |
435 | } else { | 435 | } else { |
436 | /* Signal frames without vectors registers are short ! */ | 436 | /* Signal frames without vectors registers are short ! */ |
437 | __u16 __user *svc = (void *) frame + frame_size - 2; | 437 | __u16 __user *svc = (void __user *) frame + frame_size - 2; |
438 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) | 438 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) |
439 | return -EFAULT; | 439 | return -EFAULT; |
440 | restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; | 440 | restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; |
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c index c4f7a3d655b8..d7fa2f0f1425 100644 --- a/arch/s390/kernel/compat_wrapper.c +++ b/arch/s390/kernel/compat_wrapper.c | |||
@@ -218,3 +218,5 @@ COMPAT_SYSCALL_WRAP3(seccomp, unsigned int, op, unsigned int, flags, const char | |||
218 | COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) | 218 | COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) |
219 | COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags) | 219 | COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags) |
220 | COMPAT_SYSCALL_WRAP3(bpf, int, cmd, union bpf_attr *, attr, unsigned int, size); | 220 | COMPAT_SYSCALL_WRAP3(bpf, int, cmd, union bpf_attr *, attr, unsigned int, size); |
221 | COMPAT_SYSCALL_WRAP3(s390_pci_mmio_write, const unsigned long, mmio_addr, const void __user *, user_buffer, const size_t, length); | ||
222 | COMPAT_SYSCALL_WRAP3(s390_pci_mmio_read, const unsigned long, mmio_addr, void __user *, user_buffer, const size_t, length); | ||
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index ee8390da6ea7..c1f21aca76e7 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
@@ -1019,7 +1019,7 @@ debug_count_numargs(char *string) | |||
1019 | */ | 1019 | */ |
1020 | 1020 | ||
1021 | debug_entry_t* | 1021 | debug_entry_t* |
1022 | debug_sprintf_event(debug_info_t* id, int level,char *string,...) | 1022 | __debug_sprintf_event(debug_info_t *id, int level, char *string, ...) |
1023 | { | 1023 | { |
1024 | va_list ap; | 1024 | va_list ap; |
1025 | int numargs,idx; | 1025 | int numargs,idx; |
@@ -1027,8 +1027,6 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) | |||
1027 | debug_sprintf_entry_t *curr_event; | 1027 | debug_sprintf_entry_t *curr_event; |
1028 | debug_entry_t *active; | 1028 | debug_entry_t *active; |
1029 | 1029 | ||
1030 | if((!id) || (level > id->level)) | ||
1031 | return NULL; | ||
1032 | if (!debug_active || !id->areas) | 1030 | if (!debug_active || !id->areas) |
1033 | return NULL; | 1031 | return NULL; |
1034 | numargs=debug_count_numargs(string); | 1032 | numargs=debug_count_numargs(string); |
@@ -1050,14 +1048,14 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) | |||
1050 | 1048 | ||
1051 | return active; | 1049 | return active; |
1052 | } | 1050 | } |
1053 | EXPORT_SYMBOL(debug_sprintf_event); | 1051 | EXPORT_SYMBOL(__debug_sprintf_event); |
1054 | 1052 | ||
1055 | /* | 1053 | /* |
1056 | * debug_sprintf_exception: | 1054 | * debug_sprintf_exception: |
1057 | */ | 1055 | */ |
1058 | 1056 | ||
1059 | debug_entry_t* | 1057 | debug_entry_t* |
1060 | debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | 1058 | __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...) |
1061 | { | 1059 | { |
1062 | va_list ap; | 1060 | va_list ap; |
1063 | int numargs,idx; | 1061 | int numargs,idx; |
@@ -1065,8 +1063,6 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | |||
1065 | debug_sprintf_entry_t *curr_event; | 1063 | debug_sprintf_entry_t *curr_event; |
1066 | debug_entry_t *active; | 1064 | debug_entry_t *active; |
1067 | 1065 | ||
1068 | if((!id) || (level > id->level)) | ||
1069 | return NULL; | ||
1070 | if (!debug_active || !id->areas) | 1066 | if (!debug_active || !id->areas) |
1071 | return NULL; | 1067 | return NULL; |
1072 | 1068 | ||
@@ -1089,7 +1085,7 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | |||
1089 | 1085 | ||
1090 | return active; | 1086 | return active; |
1091 | } | 1087 | } |
1092 | EXPORT_SYMBOL(debug_sprintf_exception); | 1088 | EXPORT_SYMBOL(__debug_sprintf_exception); |
1093 | 1089 | ||
1094 | /* | 1090 | /* |
1095 | * debug_register_view: | 1091 | * debug_register_view: |
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index acb412442e5e..a99852e96a77 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c | |||
@@ -191,7 +191,8 @@ void die(struct pt_regs *regs, const char *str) | |||
191 | console_verbose(); | 191 | console_verbose(); |
192 | spin_lock_irq(&die_lock); | 192 | spin_lock_irq(&die_lock); |
193 | bust_spinlocks(1); | 193 | bust_spinlocks(1); |
194 | printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter); | 194 | printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, |
195 | regs->int_code >> 17, ++die_counter); | ||
195 | #ifdef CONFIG_PREEMPT | 196 | #ifdef CONFIG_PREEMPT |
196 | printk("PREEMPT "); | 197 | printk("PREEMPT "); |
197 | #endif | 198 | #endif |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index cef2879edff3..302ac1f7f8e7 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
15 | #include <linux/ftrace.h> | ||
16 | #include <linux/lockdep.h> | 15 | #include <linux/lockdep.h> |
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/pfn.h> | 17 | #include <linux/pfn.h> |
@@ -490,8 +489,5 @@ void __init startup_init(void) | |||
490 | detect_machine_facilities(); | 489 | detect_machine_facilities(); |
491 | setup_topology(); | 490 | setup_topology(); |
492 | sclp_early_detect(); | 491 | sclp_early_detect(); |
493 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
494 | S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; | ||
495 | #endif | ||
496 | lockdep_on(); | 492 | lockdep_on(); |
497 | } | 493 | } |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 70203265196f..398329b2b518 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -53,7 +53,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
53 | .macro TRACE_IRQS_ON | 53 | .macro TRACE_IRQS_ON |
54 | #ifdef CONFIG_TRACE_IRQFLAGS | 54 | #ifdef CONFIG_TRACE_IRQFLAGS |
55 | basr %r2,%r0 | 55 | basr %r2,%r0 |
56 | l %r1,BASED(.Lhardirqs_on) | 56 | l %r1,BASED(.Lc_hardirqs_on) |
57 | basr %r14,%r1 # call trace_hardirqs_on_caller | 57 | basr %r14,%r1 # call trace_hardirqs_on_caller |
58 | #endif | 58 | #endif |
59 | .endm | 59 | .endm |
@@ -61,7 +61,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
61 | .macro TRACE_IRQS_OFF | 61 | .macro TRACE_IRQS_OFF |
62 | #ifdef CONFIG_TRACE_IRQFLAGS | 62 | #ifdef CONFIG_TRACE_IRQFLAGS |
63 | basr %r2,%r0 | 63 | basr %r2,%r0 |
64 | l %r1,BASED(.Lhardirqs_off) | 64 | l %r1,BASED(.Lc_hardirqs_off) |
65 | basr %r14,%r1 # call trace_hardirqs_off_caller | 65 | basr %r14,%r1 # call trace_hardirqs_off_caller |
66 | #endif | 66 | #endif |
67 | .endm | 67 | .endm |
@@ -70,7 +70,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
70 | #ifdef CONFIG_LOCKDEP | 70 | #ifdef CONFIG_LOCKDEP |
71 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 71 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
72 | jz .+10 | 72 | jz .+10 |
73 | l %r1,BASED(.Llockdep_sys_exit) | 73 | l %r1,BASED(.Lc_lockdep_sys_exit) |
74 | basr %r14,%r1 # call lockdep_sys_exit | 74 | basr %r14,%r1 # call lockdep_sys_exit |
75 | #endif | 75 | #endif |
76 | .endm | 76 | .endm |
@@ -87,8 +87,8 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
87 | tmh %r8,0x0001 # interrupting from user ? | 87 | tmh %r8,0x0001 # interrupting from user ? |
88 | jnz 1f | 88 | jnz 1f |
89 | lr %r14,%r9 | 89 | lr %r14,%r9 |
90 | sl %r14,BASED(.Lcritical_start) | 90 | sl %r14,BASED(.Lc_critical_start) |
91 | cl %r14,BASED(.Lcritical_length) | 91 | cl %r14,BASED(.Lc_critical_length) |
92 | jhe 0f | 92 | jhe 0f |
93 | la %r11,\savearea # inside critical section, do cleanup | 93 | la %r11,\savearea # inside critical section, do cleanup |
94 | bras %r14,cleanup_critical | 94 | bras %r14,cleanup_critical |
@@ -162,7 +162,7 @@ ENTRY(__switch_to) | |||
162 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 162 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
163 | br %r14 | 163 | br %r14 |
164 | 164 | ||
165 | __critical_start: | 165 | .L__critical_start: |
166 | /* | 166 | /* |
167 | * SVC interrupt handler routine. System calls are synchronous events and | 167 | * SVC interrupt handler routine. System calls are synchronous events and |
168 | * are executed with interrupts enabled. | 168 | * are executed with interrupts enabled. |
@@ -170,145 +170,145 @@ __critical_start: | |||
170 | 170 | ||
171 | ENTRY(system_call) | 171 | ENTRY(system_call) |
172 | stpt __LC_SYNC_ENTER_TIMER | 172 | stpt __LC_SYNC_ENTER_TIMER |
173 | sysc_stm: | 173 | .Lsysc_stm: |
174 | stm %r8,%r15,__LC_SAVE_AREA_SYNC | 174 | stm %r8,%r15,__LC_SAVE_AREA_SYNC |
175 | l %r12,__LC_THREAD_INFO | 175 | l %r12,__LC_THREAD_INFO |
176 | l %r13,__LC_SVC_NEW_PSW+4 | 176 | l %r13,__LC_SVC_NEW_PSW+4 |
177 | lhi %r14,_PIF_SYSCALL | 177 | lhi %r14,_PIF_SYSCALL |
178 | sysc_per: | 178 | .Lsysc_per: |
179 | l %r15,__LC_KERNEL_STACK | 179 | l %r15,__LC_KERNEL_STACK |
180 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | 180 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs |
181 | sysc_vtime: | 181 | .Lsysc_vtime: |
182 | UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER | 182 | UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER |
183 | stm %r0,%r7,__PT_R0(%r11) | 183 | stm %r0,%r7,__PT_R0(%r11) |
184 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC | 184 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC |
185 | mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW | 185 | mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW |
186 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC | 186 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
187 | st %r14,__PT_FLAGS(%r11) | 187 | st %r14,__PT_FLAGS(%r11) |
188 | sysc_do_svc: | 188 | .Lsysc_do_svc: |
189 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table | 189 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table |
190 | lh %r8,__PT_INT_CODE+2(%r11) | 190 | lh %r8,__PT_INT_CODE+2(%r11) |
191 | sla %r8,2 # shift and test for svc0 | 191 | sla %r8,2 # shift and test for svc0 |
192 | jnz sysc_nr_ok | 192 | jnz .Lsysc_nr_ok |
193 | # svc 0: system call number in %r1 | 193 | # svc 0: system call number in %r1 |
194 | cl %r1,BASED(.Lnr_syscalls) | 194 | cl %r1,BASED(.Lnr_syscalls) |
195 | jnl sysc_nr_ok | 195 | jnl .Lsysc_nr_ok |
196 | sth %r1,__PT_INT_CODE+2(%r11) | 196 | sth %r1,__PT_INT_CODE+2(%r11) |
197 | lr %r8,%r1 | 197 | lr %r8,%r1 |
198 | sla %r8,2 | 198 | sla %r8,2 |
199 | sysc_nr_ok: | 199 | .Lsysc_nr_ok: |
200 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 200 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
201 | st %r2,__PT_ORIG_GPR2(%r11) | 201 | st %r2,__PT_ORIG_GPR2(%r11) |
202 | st %r7,STACK_FRAME_OVERHEAD(%r15) | 202 | st %r7,STACK_FRAME_OVERHEAD(%r15) |
203 | l %r9,0(%r8,%r10) # get system call addr. | 203 | l %r9,0(%r8,%r10) # get system call addr. |
204 | tm __TI_flags+3(%r12),_TIF_TRACE | 204 | tm __TI_flags+3(%r12),_TIF_TRACE |
205 | jnz sysc_tracesys | 205 | jnz .Lsysc_tracesys |
206 | basr %r14,%r9 # call sys_xxxx | 206 | basr %r14,%r9 # call sys_xxxx |
207 | st %r2,__PT_R2(%r11) # store return value | 207 | st %r2,__PT_R2(%r11) # store return value |
208 | 208 | ||
209 | sysc_return: | 209 | .Lsysc_return: |
210 | LOCKDEP_SYS_EXIT | 210 | LOCKDEP_SYS_EXIT |
211 | sysc_tif: | 211 | .Lsysc_tif: |
212 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 212 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
213 | jno sysc_restore | 213 | jno .Lsysc_restore |
214 | tm __PT_FLAGS+3(%r11),_PIF_WORK | 214 | tm __PT_FLAGS+3(%r11),_PIF_WORK |
215 | jnz sysc_work | 215 | jnz .Lsysc_work |
216 | tm __TI_flags+3(%r12),_TIF_WORK | 216 | tm __TI_flags+3(%r12),_TIF_WORK |
217 | jnz sysc_work # check for thread work | 217 | jnz .Lsysc_work # check for thread work |
218 | tm __LC_CPU_FLAGS+3,_CIF_WORK | 218 | tm __LC_CPU_FLAGS+3,_CIF_WORK |
219 | jnz sysc_work | 219 | jnz .Lsysc_work |
220 | sysc_restore: | 220 | .Lsysc_restore: |
221 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) | 221 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
222 | stpt __LC_EXIT_TIMER | 222 | stpt __LC_EXIT_TIMER |
223 | lm %r0,%r15,__PT_R0(%r11) | 223 | lm %r0,%r15,__PT_R0(%r11) |
224 | lpsw __LC_RETURN_PSW | 224 | lpsw __LC_RETURN_PSW |
225 | sysc_done: | 225 | .Lsysc_done: |
226 | 226 | ||
227 | # | 227 | # |
228 | # One of the work bits is on. Find out which one. | 228 | # One of the work bits is on. Find out which one. |
229 | # | 229 | # |
230 | sysc_work: | 230 | .Lsysc_work: |
231 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING | 231 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING |
232 | jo sysc_mcck_pending | 232 | jo .Lsysc_mcck_pending |
233 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 233 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
234 | jo sysc_reschedule | 234 | jo .Lsysc_reschedule |
235 | tm __PT_FLAGS+3(%r11),_PIF_PER_TRAP | 235 | tm __PT_FLAGS+3(%r11),_PIF_PER_TRAP |
236 | jo sysc_singlestep | 236 | jo .Lsysc_singlestep |
237 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 237 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
238 | jo sysc_sigpending | 238 | jo .Lsysc_sigpending |
239 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 239 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
240 | jo sysc_notify_resume | 240 | jo .Lsysc_notify_resume |
241 | tm __LC_CPU_FLAGS+3,_CIF_ASCE | 241 | tm __LC_CPU_FLAGS+3,_CIF_ASCE |
242 | jo sysc_uaccess | 242 | jo .Lsysc_uaccess |
243 | j sysc_return # beware of critical section cleanup | 243 | j .Lsysc_return # beware of critical section cleanup |
244 | 244 | ||
245 | # | 245 | # |
246 | # _TIF_NEED_RESCHED is set, call schedule | 246 | # _TIF_NEED_RESCHED is set, call schedule |
247 | # | 247 | # |
248 | sysc_reschedule: | 248 | .Lsysc_reschedule: |
249 | l %r1,BASED(.Lschedule) | 249 | l %r1,BASED(.Lc_schedule) |
250 | la %r14,BASED(sysc_return) | 250 | la %r14,BASED(.Lsysc_return) |
251 | br %r1 # call schedule | 251 | br %r1 # call schedule |
252 | 252 | ||
253 | # | 253 | # |
254 | # _CIF_MCCK_PENDING is set, call handler | 254 | # _CIF_MCCK_PENDING is set, call handler |
255 | # | 255 | # |
256 | sysc_mcck_pending: | 256 | .Lsysc_mcck_pending: |
257 | l %r1,BASED(.Lhandle_mcck) | 257 | l %r1,BASED(.Lc_handle_mcck) |
258 | la %r14,BASED(sysc_return) | 258 | la %r14,BASED(.Lsysc_return) |
259 | br %r1 # TIF bit will be cleared by handler | 259 | br %r1 # TIF bit will be cleared by handler |
260 | 260 | ||
261 | # | 261 | # |
262 | # _CIF_ASCE is set, load user space asce | 262 | # _CIF_ASCE is set, load user space asce |
263 | # | 263 | # |
264 | sysc_uaccess: | 264 | .Lsysc_uaccess: |
265 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE | 265 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE |
266 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce | 266 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce |
267 | j sysc_return | 267 | j .Lsysc_return |
268 | 268 | ||
269 | # | 269 | # |
270 | # _TIF_SIGPENDING is set, call do_signal | 270 | # _TIF_SIGPENDING is set, call do_signal |
271 | # | 271 | # |
272 | sysc_sigpending: | 272 | .Lsysc_sigpending: |
273 | lr %r2,%r11 # pass pointer to pt_regs | 273 | lr %r2,%r11 # pass pointer to pt_regs |
274 | l %r1,BASED(.Ldo_signal) | 274 | l %r1,BASED(.Lc_do_signal) |
275 | basr %r14,%r1 # call do_signal | 275 | basr %r14,%r1 # call do_signal |
276 | tm __PT_FLAGS+3(%r11),_PIF_SYSCALL | 276 | tm __PT_FLAGS+3(%r11),_PIF_SYSCALL |
277 | jno sysc_return | 277 | jno .Lsysc_return |
278 | lm %r2,%r7,__PT_R2(%r11) # load svc arguments | 278 | lm %r2,%r7,__PT_R2(%r11) # load svc arguments |
279 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table | 279 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table |
280 | xr %r8,%r8 # svc 0 returns -ENOSYS | 280 | xr %r8,%r8 # svc 0 returns -ENOSYS |
281 | clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) | 281 | clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) |
282 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 282 | jnl .Lsysc_nr_ok # invalid svc number -> do svc 0 |
283 | lh %r8,__PT_INT_CODE+2(%r11) # load new svc number | 283 | lh %r8,__PT_INT_CODE+2(%r11) # load new svc number |
284 | sla %r8,2 | 284 | sla %r8,2 |
285 | j sysc_nr_ok # restart svc | 285 | j .Lsysc_nr_ok # restart svc |
286 | 286 | ||
287 | # | 287 | # |
288 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 288 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
289 | # | 289 | # |
290 | sysc_notify_resume: | 290 | .Lsysc_notify_resume: |
291 | lr %r2,%r11 # pass pointer to pt_regs | 291 | lr %r2,%r11 # pass pointer to pt_regs |
292 | l %r1,BASED(.Ldo_notify_resume) | 292 | l %r1,BASED(.Lc_do_notify_resume) |
293 | la %r14,BASED(sysc_return) | 293 | la %r14,BASED(.Lsysc_return) |
294 | br %r1 # call do_notify_resume | 294 | br %r1 # call do_notify_resume |
295 | 295 | ||
296 | # | 296 | # |
297 | # _PIF_PER_TRAP is set, call do_per_trap | 297 | # _PIF_PER_TRAP is set, call do_per_trap |
298 | # | 298 | # |
299 | sysc_singlestep: | 299 | .Lsysc_singlestep: |
300 | ni __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP | 300 | ni __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP |
301 | lr %r2,%r11 # pass pointer to pt_regs | 301 | lr %r2,%r11 # pass pointer to pt_regs |
302 | l %r1,BASED(.Ldo_per_trap) | 302 | l %r1,BASED(.Lc_do_per_trap) |
303 | la %r14,BASED(sysc_return) | 303 | la %r14,BASED(.Lsysc_return) |
304 | br %r1 # call do_per_trap | 304 | br %r1 # call do_per_trap |
305 | 305 | ||
306 | # | 306 | # |
307 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before | 307 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
308 | # and after the system call | 308 | # and after the system call |
309 | # | 309 | # |
310 | sysc_tracesys: | 310 | .Lsysc_tracesys: |
311 | l %r1,BASED(.Ltrace_enter) | 311 | l %r1,BASED(.Lc_trace_enter) |
312 | lr %r2,%r11 # pass pointer to pt_regs | 312 | lr %r2,%r11 # pass pointer to pt_regs |
313 | la %r3,0 | 313 | la %r3,0 |
314 | xr %r0,%r0 | 314 | xr %r0,%r0 |
@@ -316,22 +316,22 @@ sysc_tracesys: | |||
316 | st %r0,__PT_R2(%r11) | 316 | st %r0,__PT_R2(%r11) |
317 | basr %r14,%r1 # call do_syscall_trace_enter | 317 | basr %r14,%r1 # call do_syscall_trace_enter |
318 | cl %r2,BASED(.Lnr_syscalls) | 318 | cl %r2,BASED(.Lnr_syscalls) |
319 | jnl sysc_tracenogo | 319 | jnl .Lsysc_tracenogo |
320 | lr %r8,%r2 | 320 | lr %r8,%r2 |
321 | sll %r8,2 | 321 | sll %r8,2 |
322 | l %r9,0(%r8,%r10) | 322 | l %r9,0(%r8,%r10) |
323 | sysc_tracego: | 323 | .Lsysc_tracego: |
324 | lm %r3,%r7,__PT_R3(%r11) | 324 | lm %r3,%r7,__PT_R3(%r11) |
325 | st %r7,STACK_FRAME_OVERHEAD(%r15) | 325 | st %r7,STACK_FRAME_OVERHEAD(%r15) |
326 | l %r2,__PT_ORIG_GPR2(%r11) | 326 | l %r2,__PT_ORIG_GPR2(%r11) |
327 | basr %r14,%r9 # call sys_xxx | 327 | basr %r14,%r9 # call sys_xxx |
328 | st %r2,__PT_R2(%r11) # store return value | 328 | st %r2,__PT_R2(%r11) # store return value |
329 | sysc_tracenogo: | 329 | .Lsysc_tracenogo: |
330 | tm __TI_flags+3(%r12),_TIF_TRACE | 330 | tm __TI_flags+3(%r12),_TIF_TRACE |
331 | jz sysc_return | 331 | jz .Lsysc_return |
332 | l %r1,BASED(.Ltrace_exit) | 332 | l %r1,BASED(.Lc_trace_exit) |
333 | lr %r2,%r11 # pass pointer to pt_regs | 333 | lr %r2,%r11 # pass pointer to pt_regs |
334 | la %r14,BASED(sysc_return) | 334 | la %r14,BASED(.Lsysc_return) |
335 | br %r1 # call do_syscall_trace_exit | 335 | br %r1 # call do_syscall_trace_exit |
336 | 336 | ||
337 | # | 337 | # |
@@ -341,18 +341,18 @@ ENTRY(ret_from_fork) | |||
341 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 341 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
342 | l %r12,__LC_THREAD_INFO | 342 | l %r12,__LC_THREAD_INFO |
343 | l %r13,__LC_SVC_NEW_PSW+4 | 343 | l %r13,__LC_SVC_NEW_PSW+4 |
344 | l %r1,BASED(.Lschedule_tail) | 344 | l %r1,BASED(.Lc_schedule_tail) |
345 | basr %r14,%r1 # call schedule_tail | 345 | basr %r14,%r1 # call schedule_tail |
346 | TRACE_IRQS_ON | 346 | TRACE_IRQS_ON |
347 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 347 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
348 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | 348 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
349 | jne sysc_tracenogo | 349 | jne .Lsysc_tracenogo |
350 | # it's a kernel thread | 350 | # it's a kernel thread |
351 | lm %r9,%r10,__PT_R9(%r11) # load gprs | 351 | lm %r9,%r10,__PT_R9(%r11) # load gprs |
352 | ENTRY(kernel_thread_starter) | 352 | ENTRY(kernel_thread_starter) |
353 | la %r2,0(%r10) | 353 | la %r2,0(%r10) |
354 | basr %r14,%r9 | 354 | basr %r14,%r9 |
355 | j sysc_tracenogo | 355 | j .Lsysc_tracenogo |
356 | 356 | ||
357 | /* | 357 | /* |
358 | * Program check handler routine | 358 | * Program check handler routine |
@@ -369,7 +369,7 @@ ENTRY(pgm_check_handler) | |||
369 | tmh %r8,0x4000 # PER bit set in old PSW ? | 369 | tmh %r8,0x4000 # PER bit set in old PSW ? |
370 | jnz 0f # -> enabled, can't be a double fault | 370 | jnz 0f # -> enabled, can't be a double fault |
371 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 371 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
372 | jnz pgm_svcper # -> single stepped svc | 372 | jnz .Lpgm_svcper # -> single stepped svc |
373 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC | 373 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
374 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 374 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
375 | j 2f | 375 | j 2f |
@@ -386,42 +386,42 @@ ENTRY(pgm_check_handler) | |||
386 | jz 0f | 386 | jz 0f |
387 | l %r1,__TI_task(%r12) | 387 | l %r1,__TI_task(%r12) |
388 | tmh %r8,0x0001 # kernel per event ? | 388 | tmh %r8,0x0001 # kernel per event ? |
389 | jz pgm_kprobe | 389 | jz .Lpgm_kprobe |
390 | oi __PT_FLAGS+3(%r11),_PIF_PER_TRAP | 390 | oi __PT_FLAGS+3(%r11),_PIF_PER_TRAP |
391 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS | 391 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS |
392 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CODE | 392 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CODE |
393 | mvc __THREAD_per_paid(1,%r1),__LC_PER_ACCESS_ID | 393 | mvc __THREAD_per_paid(1,%r1),__LC_PER_ACCESS_ID |
394 | 0: REENABLE_IRQS | 394 | 0: REENABLE_IRQS |
395 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 395 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
396 | l %r1,BASED(.Ljump_table) | 396 | l %r1,BASED(.Lc_jump_table) |
397 | la %r10,0x7f | 397 | la %r10,0x7f |
398 | n %r10,__PT_INT_CODE(%r11) | 398 | n %r10,__PT_INT_CODE(%r11) |
399 | je sysc_return | 399 | je .Lsysc_return |
400 | sll %r10,2 | 400 | sll %r10,2 |
401 | l %r1,0(%r10,%r1) # load address of handler routine | 401 | l %r1,0(%r10,%r1) # load address of handler routine |
402 | lr %r2,%r11 # pass pointer to pt_regs | 402 | lr %r2,%r11 # pass pointer to pt_regs |
403 | basr %r14,%r1 # branch to interrupt-handler | 403 | basr %r14,%r1 # branch to interrupt-handler |
404 | j sysc_return | 404 | j .Lsysc_return |
405 | 405 | ||
406 | # | 406 | # |
407 | # PER event in supervisor state, must be kprobes | 407 | # PER event in supervisor state, must be kprobes |
408 | # | 408 | # |
409 | pgm_kprobe: | 409 | .Lpgm_kprobe: |
410 | REENABLE_IRQS | 410 | REENABLE_IRQS |
411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
412 | l %r1,BASED(.Ldo_per_trap) | 412 | l %r1,BASED(.Lc_do_per_trap) |
413 | lr %r2,%r11 # pass pointer to pt_regs | 413 | lr %r2,%r11 # pass pointer to pt_regs |
414 | basr %r14,%r1 # call do_per_trap | 414 | basr %r14,%r1 # call do_per_trap |
415 | j sysc_return | 415 | j .Lsysc_return |
416 | 416 | ||
417 | # | 417 | # |
418 | # single stepped system call | 418 | # single stepped system call |
419 | # | 419 | # |
420 | pgm_svcper: | 420 | .Lpgm_svcper: |
421 | mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW | 421 | mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW |
422 | mvc __LC_RETURN_PSW+4(4),BASED(.Lsysc_per) | 422 | mvc __LC_RETURN_PSW+4(4),BASED(.Lc_sysc_per) |
423 | lhi %r14,_PIF_SYSCALL | _PIF_PER_TRAP | 423 | lhi %r14,_PIF_SYSCALL | _PIF_PER_TRAP |
424 | lpsw __LC_RETURN_PSW # branch to sysc_per and enable irqs | 424 | lpsw __LC_RETURN_PSW # branch to .Lsysc_per and enable irqs |
425 | 425 | ||
426 | /* | 426 | /* |
427 | * IO interrupt handler routine | 427 | * IO interrupt handler routine |
@@ -435,9 +435,9 @@ ENTRY(io_int_handler) | |||
435 | l %r13,__LC_SVC_NEW_PSW+4 | 435 | l %r13,__LC_SVC_NEW_PSW+4 |
436 | lm %r8,%r9,__LC_IO_OLD_PSW | 436 | lm %r8,%r9,__LC_IO_OLD_PSW |
437 | tmh %r8,0x0001 # interrupting from user ? | 437 | tmh %r8,0x0001 # interrupting from user ? |
438 | jz io_skip | 438 | jz .Lio_skip |
439 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER | 439 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
440 | io_skip: | 440 | .Lio_skip: |
441 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 441 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
442 | stm %r0,%r7,__PT_R0(%r11) | 442 | stm %r0,%r7,__PT_R0(%r11) |
443 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 443 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
@@ -446,35 +446,35 @@ io_skip: | |||
446 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 446 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
447 | TRACE_IRQS_OFF | 447 | TRACE_IRQS_OFF |
448 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 448 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
449 | io_loop: | 449 | .Lio_loop: |
450 | l %r1,BASED(.Ldo_IRQ) | 450 | l %r1,BASED(.Lc_do_IRQ) |
451 | lr %r2,%r11 # pass pointer to pt_regs | 451 | lr %r2,%r11 # pass pointer to pt_regs |
452 | lhi %r3,IO_INTERRUPT | 452 | lhi %r3,IO_INTERRUPT |
453 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? | 453 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? |
454 | jz io_call | 454 | jz .Lio_call |
455 | lhi %r3,THIN_INTERRUPT | 455 | lhi %r3,THIN_INTERRUPT |
456 | io_call: | 456 | .Lio_call: |
457 | basr %r14,%r1 # call do_IRQ | 457 | basr %r14,%r1 # call do_IRQ |
458 | tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR | 458 | tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR |
459 | jz io_return | 459 | jz .Lio_return |
460 | tpi 0 | 460 | tpi 0 |
461 | jz io_return | 461 | jz .Lio_return |
462 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | 462 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID |
463 | j io_loop | 463 | j .Lio_loop |
464 | io_return: | 464 | .Lio_return: |
465 | LOCKDEP_SYS_EXIT | 465 | LOCKDEP_SYS_EXIT |
466 | TRACE_IRQS_ON | 466 | TRACE_IRQS_ON |
467 | io_tif: | 467 | .Lio_tif: |
468 | tm __TI_flags+3(%r12),_TIF_WORK | 468 | tm __TI_flags+3(%r12),_TIF_WORK |
469 | jnz io_work # there is work to do (signals etc.) | 469 | jnz .Lio_work # there is work to do (signals etc.) |
470 | tm __LC_CPU_FLAGS+3,_CIF_WORK | 470 | tm __LC_CPU_FLAGS+3,_CIF_WORK |
471 | jnz io_work | 471 | jnz .Lio_work |
472 | io_restore: | 472 | .Lio_restore: |
473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) | 473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
474 | stpt __LC_EXIT_TIMER | 474 | stpt __LC_EXIT_TIMER |
475 | lm %r0,%r15,__PT_R0(%r11) | 475 | lm %r0,%r15,__PT_R0(%r11) |
476 | lpsw __LC_RETURN_PSW | 476 | lpsw __LC_RETURN_PSW |
477 | io_done: | 477 | .Lio_done: |
478 | 478 | ||
479 | # | 479 | # |
480 | # There is work todo, find out in which context we have been interrupted: | 480 | # There is work todo, find out in which context we have been interrupted: |
@@ -483,15 +483,15 @@ io_done: | |||
483 | # the preemption counter and if it is zero call preempt_schedule_irq | 483 | # the preemption counter and if it is zero call preempt_schedule_irq |
484 | # Before any work can be done, a switch to the kernel stack is required. | 484 | # Before any work can be done, a switch to the kernel stack is required. |
485 | # | 485 | # |
486 | io_work: | 486 | .Lio_work: |
487 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 487 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
488 | jo io_work_user # yes -> do resched & signal | 488 | jo .Lio_work_user # yes -> do resched & signal |
489 | #ifdef CONFIG_PREEMPT | 489 | #ifdef CONFIG_PREEMPT |
490 | # check for preemptive scheduling | 490 | # check for preemptive scheduling |
491 | icm %r0,15,__TI_precount(%r12) | 491 | icm %r0,15,__TI_precount(%r12) |
492 | jnz io_restore # preemption disabled | 492 | jnz .Lio_restore # preemption disabled |
493 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 493 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
494 | jno io_restore | 494 | jno .Lio_restore |
495 | # switch to kernel stack | 495 | # switch to kernel stack |
496 | l %r1,__PT_R15(%r11) | 496 | l %r1,__PT_R15(%r11) |
497 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 497 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
@@ -499,20 +499,20 @@ io_work: | |||
499 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 499 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
500 | la %r11,STACK_FRAME_OVERHEAD(%r1) | 500 | la %r11,STACK_FRAME_OVERHEAD(%r1) |
501 | lr %r15,%r1 | 501 | lr %r15,%r1 |
502 | # TRACE_IRQS_ON already done at io_return, call | 502 | # TRACE_IRQS_ON already done at .Lio_return, call |
503 | # TRACE_IRQS_OFF to keep things symmetrical | 503 | # TRACE_IRQS_OFF to keep things symmetrical |
504 | TRACE_IRQS_OFF | 504 | TRACE_IRQS_OFF |
505 | l %r1,BASED(.Lpreempt_irq) | 505 | l %r1,BASED(.Lc_preempt_irq) |
506 | basr %r14,%r1 # call preempt_schedule_irq | 506 | basr %r14,%r1 # call preempt_schedule_irq |
507 | j io_return | 507 | j .Lio_return |
508 | #else | 508 | #else |
509 | j io_restore | 509 | j .Lio_restore |
510 | #endif | 510 | #endif |
511 | 511 | ||
512 | # | 512 | # |
513 | # Need to do work before returning to userspace, switch to kernel stack | 513 | # Need to do work before returning to userspace, switch to kernel stack |
514 | # | 514 | # |
515 | io_work_user: | 515 | .Lio_work_user: |
516 | l %r1,__LC_KERNEL_STACK | 516 | l %r1,__LC_KERNEL_STACK |
517 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 517 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
518 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 518 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
@@ -522,74 +522,74 @@ io_work_user: | |||
522 | # | 522 | # |
523 | # One of the work bits is on. Find out which one. | 523 | # One of the work bits is on. Find out which one. |
524 | # | 524 | # |
525 | io_work_tif: | 525 | .Lio_work_tif: |
526 | tm __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING | 526 | tm __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING |
527 | jo io_mcck_pending | 527 | jo .Lio_mcck_pending |
528 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 528 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
529 | jo io_reschedule | 529 | jo .Lio_reschedule |
530 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 530 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
531 | jo io_sigpending | 531 | jo .Lio_sigpending |
532 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 532 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
533 | jo io_notify_resume | 533 | jo .Lio_notify_resume |
534 | tm __LC_CPU_FLAGS+3,_CIF_ASCE | 534 | tm __LC_CPU_FLAGS+3,_CIF_ASCE |
535 | jo io_uaccess | 535 | jo .Lio_uaccess |
536 | j io_return # beware of critical section cleanup | 536 | j .Lio_return # beware of critical section cleanup |
537 | 537 | ||
538 | # | 538 | # |
539 | # _CIF_MCCK_PENDING is set, call handler | 539 | # _CIF_MCCK_PENDING is set, call handler |
540 | # | 540 | # |
541 | io_mcck_pending: | 541 | .Lio_mcck_pending: |
542 | # TRACE_IRQS_ON already done at io_return | 542 | # TRACE_IRQS_ON already done at .Lio_return |
543 | l %r1,BASED(.Lhandle_mcck) | 543 | l %r1,BASED(.Lc_handle_mcck) |
544 | basr %r14,%r1 # TIF bit will be cleared by handler | 544 | basr %r14,%r1 # TIF bit will be cleared by handler |
545 | TRACE_IRQS_OFF | 545 | TRACE_IRQS_OFF |
546 | j io_return | 546 | j .Lio_return |
547 | 547 | ||
548 | # | 548 | # |
549 | # _CIF_ASCE is set, load user space asce | 549 | # _CIF_ASCE is set, load user space asce |
550 | # | 550 | # |
551 | io_uaccess: | 551 | .Lio_uaccess: |
552 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE | 552 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE |
553 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce | 553 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce |
554 | j io_return | 554 | j .Lio_return |
555 | 555 | ||
556 | # | 556 | # |
557 | # _TIF_NEED_RESCHED is set, call schedule | 557 | # _TIF_NEED_RESCHED is set, call schedule |
558 | # | 558 | # |
559 | io_reschedule: | 559 | .Lio_reschedule: |
560 | # TRACE_IRQS_ON already done at io_return | 560 | # TRACE_IRQS_ON already done at .Lio_return |
561 | l %r1,BASED(.Lschedule) | 561 | l %r1,BASED(.Lc_schedule) |
562 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 562 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
563 | basr %r14,%r1 # call scheduler | 563 | basr %r14,%r1 # call scheduler |
564 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 564 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
565 | TRACE_IRQS_OFF | 565 | TRACE_IRQS_OFF |
566 | j io_return | 566 | j .Lio_return |
567 | 567 | ||
568 | # | 568 | # |
569 | # _TIF_SIGPENDING is set, call do_signal | 569 | # _TIF_SIGPENDING is set, call do_signal |
570 | # | 570 | # |
571 | io_sigpending: | 571 | .Lio_sigpending: |
572 | # TRACE_IRQS_ON already done at io_return | 572 | # TRACE_IRQS_ON already done at .Lio_return |
573 | l %r1,BASED(.Ldo_signal) | 573 | l %r1,BASED(.Lc_do_signal) |
574 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 574 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
575 | lr %r2,%r11 # pass pointer to pt_regs | 575 | lr %r2,%r11 # pass pointer to pt_regs |
576 | basr %r14,%r1 # call do_signal | 576 | basr %r14,%r1 # call do_signal |
577 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 577 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
578 | TRACE_IRQS_OFF | 578 | TRACE_IRQS_OFF |
579 | j io_return | 579 | j .Lio_return |
580 | 580 | ||
581 | # | 581 | # |
582 | # _TIF_SIGPENDING is set, call do_signal | 582 | # _TIF_SIGPENDING is set, call do_signal |
583 | # | 583 | # |
584 | io_notify_resume: | 584 | .Lio_notify_resume: |
585 | # TRACE_IRQS_ON already done at io_return | 585 | # TRACE_IRQS_ON already done at .Lio_return |
586 | l %r1,BASED(.Ldo_notify_resume) | 586 | l %r1,BASED(.Lc_do_notify_resume) |
587 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 587 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
588 | lr %r2,%r11 # pass pointer to pt_regs | 588 | lr %r2,%r11 # pass pointer to pt_regs |
589 | basr %r14,%r1 # call do_notify_resume | 589 | basr %r14,%r1 # call do_notify_resume |
590 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 590 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
591 | TRACE_IRQS_OFF | 591 | TRACE_IRQS_OFF |
592 | j io_return | 592 | j .Lio_return |
593 | 593 | ||
594 | /* | 594 | /* |
595 | * External interrupt handler routine | 595 | * External interrupt handler routine |
@@ -603,9 +603,9 @@ ENTRY(ext_int_handler) | |||
603 | l %r13,__LC_SVC_NEW_PSW+4 | 603 | l %r13,__LC_SVC_NEW_PSW+4 |
604 | lm %r8,%r9,__LC_EXT_OLD_PSW | 604 | lm %r8,%r9,__LC_EXT_OLD_PSW |
605 | tmh %r8,0x0001 # interrupting from user ? | 605 | tmh %r8,0x0001 # interrupting from user ? |
606 | jz ext_skip | 606 | jz .Lext_skip |
607 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER | 607 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
608 | ext_skip: | 608 | .Lext_skip: |
609 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 609 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
610 | stm %r0,%r7,__PT_R0(%r11) | 610 | stm %r0,%r7,__PT_R0(%r11) |
611 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 611 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
@@ -614,29 +614,29 @@ ext_skip: | |||
614 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS | 614 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS |
615 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 615 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
616 | TRACE_IRQS_OFF | 616 | TRACE_IRQS_OFF |
617 | l %r1,BASED(.Ldo_IRQ) | 617 | l %r1,BASED(.Lc_do_IRQ) |
618 | lr %r2,%r11 # pass pointer to pt_regs | 618 | lr %r2,%r11 # pass pointer to pt_regs |
619 | lhi %r3,EXT_INTERRUPT | 619 | lhi %r3,EXT_INTERRUPT |
620 | basr %r14,%r1 # call do_IRQ | 620 | basr %r14,%r1 # call do_IRQ |
621 | j io_return | 621 | j .Lio_return |
622 | 622 | ||
623 | /* | 623 | /* |
624 | * Load idle PSW. The second "half" of this function is in cleanup_idle. | 624 | * Load idle PSW. The second "half" of this function is in .Lcleanup_idle. |
625 | */ | 625 | */ |
626 | ENTRY(psw_idle) | 626 | ENTRY(psw_idle) |
627 | st %r3,__SF_EMPTY(%r15) | 627 | st %r3,__SF_EMPTY(%r15) |
628 | basr %r1,0 | 628 | basr %r1,0 |
629 | la %r1,psw_idle_lpsw+4-.(%r1) | 629 | la %r1,.Lpsw_idle_lpsw+4-.(%r1) |
630 | st %r1,__SF_EMPTY+4(%r15) | 630 | st %r1,__SF_EMPTY+4(%r15) |
631 | oi __SF_EMPTY+4(%r15),0x80 | 631 | oi __SF_EMPTY+4(%r15),0x80 |
632 | stck __CLOCK_IDLE_ENTER(%r2) | 632 | stck __CLOCK_IDLE_ENTER(%r2) |
633 | stpt __TIMER_IDLE_ENTER(%r2) | 633 | stpt __TIMER_IDLE_ENTER(%r2) |
634 | psw_idle_lpsw: | 634 | .Lpsw_idle_lpsw: |
635 | lpsw __SF_EMPTY(%r15) | 635 | lpsw __SF_EMPTY(%r15) |
636 | br %r14 | 636 | br %r14 |
637 | psw_idle_end: | 637 | .Lpsw_idle_end: |
638 | 638 | ||
639 | __critical_end: | 639 | .L__critical_end: |
640 | 640 | ||
641 | /* | 641 | /* |
642 | * Machine check handler routines | 642 | * Machine check handler routines |
@@ -650,7 +650,7 @@ ENTRY(mcck_int_handler) | |||
650 | l %r13,__LC_SVC_NEW_PSW+4 | 650 | l %r13,__LC_SVC_NEW_PSW+4 |
651 | lm %r8,%r9,__LC_MCK_OLD_PSW | 651 | lm %r8,%r9,__LC_MCK_OLD_PSW |
652 | tm __LC_MCCK_CODE,0x80 # system damage? | 652 | tm __LC_MCCK_CODE,0x80 # system damage? |
653 | jo mcck_panic # yes -> rest of mcck code invalid | 653 | jo .Lmcck_panic # yes -> rest of mcck code invalid |
654 | la %r14,__LC_CPU_TIMER_SAVE_AREA | 654 | la %r14,__LC_CPU_TIMER_SAVE_AREA |
655 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 655 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
656 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 656 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
@@ -668,22 +668,22 @@ ENTRY(mcck_int_handler) | |||
668 | 2: spt 0(%r14) | 668 | 2: spt 0(%r14) |
669 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 669 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
670 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 670 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
671 | jno mcck_panic # no -> skip cleanup critical | 671 | jno .Lmcck_panic # no -> skip cleanup critical |
672 | tm %r8,0x0001 # interrupting from user ? | 672 | tm %r8,0x0001 # interrupting from user ? |
673 | jz mcck_skip | 673 | jz .Lmcck_skip |
674 | UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER | 674 | UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER |
675 | mcck_skip: | 675 | .Lmcck_skip: |
676 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT | 676 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT |
677 | stm %r0,%r7,__PT_R0(%r11) | 677 | stm %r0,%r7,__PT_R0(%r11) |
678 | mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32 | 678 | mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32 |
679 | stm %r8,%r9,__PT_PSW(%r11) | 679 | stm %r8,%r9,__PT_PSW(%r11) |
680 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 680 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
681 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 681 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
682 | l %r1,BASED(.Ldo_machine_check) | 682 | l %r1,BASED(.Lc_do_machine_check) |
683 | lr %r2,%r11 # pass pointer to pt_regs | 683 | lr %r2,%r11 # pass pointer to pt_regs |
684 | basr %r14,%r1 # call s390_do_machine_check | 684 | basr %r14,%r1 # call s390_do_machine_check |
685 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 685 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
686 | jno mcck_return | 686 | jno .Lmcck_return |
687 | l %r1,__LC_KERNEL_STACK # switch to kernel stack | 687 | l %r1,__LC_KERNEL_STACK # switch to kernel stack |
688 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 688 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
689 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 689 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
@@ -691,12 +691,12 @@ mcck_skip: | |||
691 | lr %r15,%r1 | 691 | lr %r15,%r1 |
692 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off | 692 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
693 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING | 693 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING |
694 | jno mcck_return | 694 | jno .Lmcck_return |
695 | TRACE_IRQS_OFF | 695 | TRACE_IRQS_OFF |
696 | l %r1,BASED(.Lhandle_mcck) | 696 | l %r1,BASED(.Lc_handle_mcck) |
697 | basr %r14,%r1 # call s390_handle_mcck | 697 | basr %r14,%r1 # call s390_handle_mcck |
698 | TRACE_IRQS_ON | 698 | TRACE_IRQS_ON |
699 | mcck_return: | 699 | .Lmcck_return: |
700 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW | 700 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW |
701 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 701 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
702 | jno 0f | 702 | jno 0f |
@@ -706,15 +706,15 @@ mcck_return: | |||
706 | 0: lm %r0,%r15,__PT_R0(%r11) | 706 | 0: lm %r0,%r15,__PT_R0(%r11) |
707 | lpsw __LC_RETURN_MCCK_PSW | 707 | lpsw __LC_RETURN_MCCK_PSW |
708 | 708 | ||
709 | mcck_panic: | 709 | .Lmcck_panic: |
710 | l %r14,__LC_PANIC_STACK | 710 | l %r14,__LC_PANIC_STACK |
711 | slr %r14,%r15 | 711 | slr %r14,%r15 |
712 | sra %r14,PAGE_SHIFT | 712 | sra %r14,PAGE_SHIFT |
713 | jz 0f | 713 | jz 0f |
714 | l %r15,__LC_PANIC_STACK | 714 | l %r15,__LC_PANIC_STACK |
715 | j mcck_skip | 715 | j .Lmcck_skip |
716 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 716 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
717 | j mcck_skip | 717 | j .Lmcck_skip |
718 | 718 | ||
719 | # | 719 | # |
720 | # PSW restart interrupt handler | 720 | # PSW restart interrupt handler |
@@ -764,58 +764,58 @@ stack_overflow: | |||
764 | 1: .long kernel_stack_overflow | 764 | 1: .long kernel_stack_overflow |
765 | #endif | 765 | #endif |
766 | 766 | ||
767 | cleanup_table: | 767 | .Lcleanup_table: |
768 | .long system_call + 0x80000000 | 768 | .long system_call + 0x80000000 |
769 | .long sysc_do_svc + 0x80000000 | 769 | .long .Lsysc_do_svc + 0x80000000 |
770 | .long sysc_tif + 0x80000000 | 770 | .long .Lsysc_tif + 0x80000000 |
771 | .long sysc_restore + 0x80000000 | 771 | .long .Lsysc_restore + 0x80000000 |
772 | .long sysc_done + 0x80000000 | 772 | .long .Lsysc_done + 0x80000000 |
773 | .long io_tif + 0x80000000 | 773 | .long .Lio_tif + 0x80000000 |
774 | .long io_restore + 0x80000000 | 774 | .long .Lio_restore + 0x80000000 |
775 | .long io_done + 0x80000000 | 775 | .long .Lio_done + 0x80000000 |
776 | .long psw_idle + 0x80000000 | 776 | .long psw_idle + 0x80000000 |
777 | .long psw_idle_end + 0x80000000 | 777 | .long .Lpsw_idle_end + 0x80000000 |
778 | 778 | ||
779 | cleanup_critical: | 779 | cleanup_critical: |
780 | cl %r9,BASED(cleanup_table) # system_call | 780 | cl %r9,BASED(.Lcleanup_table) # system_call |
781 | jl 0f | 781 | jl 0f |
782 | cl %r9,BASED(cleanup_table+4) # sysc_do_svc | 782 | cl %r9,BASED(.Lcleanup_table+4) # .Lsysc_do_svc |
783 | jl cleanup_system_call | 783 | jl .Lcleanup_system_call |
784 | cl %r9,BASED(cleanup_table+8) # sysc_tif | 784 | cl %r9,BASED(.Lcleanup_table+8) # .Lsysc_tif |
785 | jl 0f | 785 | jl 0f |
786 | cl %r9,BASED(cleanup_table+12) # sysc_restore | 786 | cl %r9,BASED(.Lcleanup_table+12) # .Lsysc_restore |
787 | jl cleanup_sysc_tif | 787 | jl .Lcleanup_sysc_tif |
788 | cl %r9,BASED(cleanup_table+16) # sysc_done | 788 | cl %r9,BASED(.Lcleanup_table+16) # .Lsysc_done |
789 | jl cleanup_sysc_restore | 789 | jl .Lcleanup_sysc_restore |
790 | cl %r9,BASED(cleanup_table+20) # io_tif | 790 | cl %r9,BASED(.Lcleanup_table+20) # .Lio_tif |
791 | jl 0f | 791 | jl 0f |
792 | cl %r9,BASED(cleanup_table+24) # io_restore | 792 | cl %r9,BASED(.Lcleanup_table+24) # .Lio_restore |
793 | jl cleanup_io_tif | 793 | jl .Lcleanup_io_tif |
794 | cl %r9,BASED(cleanup_table+28) # io_done | 794 | cl %r9,BASED(.Lcleanup_table+28) # .Lio_done |
795 | jl cleanup_io_restore | 795 | jl .Lcleanup_io_restore |
796 | cl %r9,BASED(cleanup_table+32) # psw_idle | 796 | cl %r9,BASED(.Lcleanup_table+32) # psw_idle |
797 | jl 0f | 797 | jl 0f |
798 | cl %r9,BASED(cleanup_table+36) # psw_idle_end | 798 | cl %r9,BASED(.Lcleanup_table+36) # .Lpsw_idle_end |
799 | jl cleanup_idle | 799 | jl .Lcleanup_idle |
800 | 0: br %r14 | 800 | 0: br %r14 |
801 | 801 | ||
802 | cleanup_system_call: | 802 | .Lcleanup_system_call: |
803 | # check if stpt has been executed | 803 | # check if stpt has been executed |
804 | cl %r9,BASED(cleanup_system_call_insn) | 804 | cl %r9,BASED(.Lcleanup_system_call_insn) |
805 | jh 0f | 805 | jh 0f |
806 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 806 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
807 | chi %r11,__LC_SAVE_AREA_ASYNC | 807 | chi %r11,__LC_SAVE_AREA_ASYNC |
808 | je 0f | 808 | je 0f |
809 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | 809 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
810 | 0: # check if stm has been executed | 810 | 0: # check if stm has been executed |
811 | cl %r9,BASED(cleanup_system_call_insn+4) | 811 | cl %r9,BASED(.Lcleanup_system_call_insn+4) |
812 | jh 0f | 812 | jh 0f |
813 | mvc __LC_SAVE_AREA_SYNC(32),0(%r11) | 813 | mvc __LC_SAVE_AREA_SYNC(32),0(%r11) |
814 | 0: # set up saved registers r12, and r13 | 814 | 0: # set up saved registers r12, and r13 |
815 | st %r12,16(%r11) # r12 thread-info pointer | 815 | st %r12,16(%r11) # r12 thread-info pointer |
816 | st %r13,20(%r11) # r13 literal-pool pointer | 816 | st %r13,20(%r11) # r13 literal-pool pointer |
817 | # check if the user time calculation has been done | 817 | # check if the user time calculation has been done |
818 | cl %r9,BASED(cleanup_system_call_insn+8) | 818 | cl %r9,BASED(.Lcleanup_system_call_insn+8) |
819 | jh 0f | 819 | jh 0f |
820 | l %r10,__LC_EXIT_TIMER | 820 | l %r10,__LC_EXIT_TIMER |
821 | l %r15,__LC_EXIT_TIMER+4 | 821 | l %r15,__LC_EXIT_TIMER+4 |
@@ -824,7 +824,7 @@ cleanup_system_call: | |||
824 | st %r10,__LC_USER_TIMER | 824 | st %r10,__LC_USER_TIMER |
825 | st %r15,__LC_USER_TIMER+4 | 825 | st %r15,__LC_USER_TIMER+4 |
826 | 0: # check if the system time calculation has been done | 826 | 0: # check if the system time calculation has been done |
827 | cl %r9,BASED(cleanup_system_call_insn+12) | 827 | cl %r9,BASED(.Lcleanup_system_call_insn+12) |
828 | jh 0f | 828 | jh 0f |
829 | l %r10,__LC_LAST_UPDATE_TIMER | 829 | l %r10,__LC_LAST_UPDATE_TIMER |
830 | l %r15,__LC_LAST_UPDATE_TIMER+4 | 830 | l %r15,__LC_LAST_UPDATE_TIMER+4 |
@@ -848,20 +848,20 @@ cleanup_system_call: | |||
848 | # setup saved register 15 | 848 | # setup saved register 15 |
849 | st %r15,28(%r11) # r15 stack pointer | 849 | st %r15,28(%r11) # r15 stack pointer |
850 | # set new psw address and exit | 850 | # set new psw address and exit |
851 | l %r9,BASED(cleanup_table+4) # sysc_do_svc + 0x80000000 | 851 | l %r9,BASED(.Lcleanup_table+4) # .Lsysc_do_svc + 0x80000000 |
852 | br %r14 | 852 | br %r14 |
853 | cleanup_system_call_insn: | 853 | .Lcleanup_system_call_insn: |
854 | .long system_call + 0x80000000 | 854 | .long system_call + 0x80000000 |
855 | .long sysc_stm + 0x80000000 | 855 | .long .Lsysc_stm + 0x80000000 |
856 | .long sysc_vtime + 0x80000000 + 36 | 856 | .long .Lsysc_vtime + 0x80000000 + 36 |
857 | .long sysc_vtime + 0x80000000 + 76 | 857 | .long .Lsysc_vtime + 0x80000000 + 76 |
858 | 858 | ||
859 | cleanup_sysc_tif: | 859 | .Lcleanup_sysc_tif: |
860 | l %r9,BASED(cleanup_table+8) # sysc_tif + 0x80000000 | 860 | l %r9,BASED(.Lcleanup_table+8) # .Lsysc_tif + 0x80000000 |
861 | br %r14 | 861 | br %r14 |
862 | 862 | ||
863 | cleanup_sysc_restore: | 863 | .Lcleanup_sysc_restore: |
864 | cl %r9,BASED(cleanup_sysc_restore_insn) | 864 | cl %r9,BASED(.Lcleanup_sysc_restore_insn) |
865 | jhe 0f | 865 | jhe 0f |
866 | l %r9,12(%r11) # get saved pointer to pt_regs | 866 | l %r9,12(%r11) # get saved pointer to pt_regs |
867 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) | 867 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
@@ -869,15 +869,15 @@ cleanup_sysc_restore: | |||
869 | lm %r0,%r7,__PT_R0(%r9) | 869 | lm %r0,%r7,__PT_R0(%r9) |
870 | 0: lm %r8,%r9,__LC_RETURN_PSW | 870 | 0: lm %r8,%r9,__LC_RETURN_PSW |
871 | br %r14 | 871 | br %r14 |
872 | cleanup_sysc_restore_insn: | 872 | .Lcleanup_sysc_restore_insn: |
873 | .long sysc_done - 4 + 0x80000000 | 873 | .long .Lsysc_done - 4 + 0x80000000 |
874 | 874 | ||
875 | cleanup_io_tif: | 875 | .Lcleanup_io_tif: |
876 | l %r9,BASED(cleanup_table+20) # io_tif + 0x80000000 | 876 | l %r9,BASED(.Lcleanup_table+20) # .Lio_tif + 0x80000000 |
877 | br %r14 | 877 | br %r14 |
878 | 878 | ||
879 | cleanup_io_restore: | 879 | .Lcleanup_io_restore: |
880 | cl %r9,BASED(cleanup_io_restore_insn) | 880 | cl %r9,BASED(.Lcleanup_io_restore_insn) |
881 | jhe 0f | 881 | jhe 0f |
882 | l %r9,12(%r11) # get saved r11 pointer to pt_regs | 882 | l %r9,12(%r11) # get saved r11 pointer to pt_regs |
883 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) | 883 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
@@ -885,10 +885,10 @@ cleanup_io_restore: | |||
885 | lm %r0,%r7,__PT_R0(%r9) | 885 | lm %r0,%r7,__PT_R0(%r9) |
886 | 0: lm %r8,%r9,__LC_RETURN_PSW | 886 | 0: lm %r8,%r9,__LC_RETURN_PSW |
887 | br %r14 | 887 | br %r14 |
888 | cleanup_io_restore_insn: | 888 | .Lcleanup_io_restore_insn: |
889 | .long io_done - 4 + 0x80000000 | 889 | .long .Lio_done - 4 + 0x80000000 |
890 | 890 | ||
891 | cleanup_idle: | 891 | .Lcleanup_idle: |
892 | # copy interrupt clock & cpu timer | 892 | # copy interrupt clock & cpu timer |
893 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK | 893 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK |
894 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER | 894 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER |
@@ -897,7 +897,7 @@ cleanup_idle: | |||
897 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK | 897 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK |
898 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER | 898 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER |
899 | 0: # check if stck has been executed | 899 | 0: # check if stck has been executed |
900 | cl %r9,BASED(cleanup_idle_insn) | 900 | cl %r9,BASED(.Lcleanup_idle_insn) |
901 | jhe 1f | 901 | jhe 1f |
902 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) | 902 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) |
903 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r3) | 903 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r3) |
@@ -913,12 +913,12 @@ cleanup_idle: | |||
913 | stm %r9,%r10,__LC_SYSTEM_TIMER | 913 | stm %r9,%r10,__LC_SYSTEM_TIMER |
914 | mvc __LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2) | 914 | mvc __LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2) |
915 | # prepare return psw | 915 | # prepare return psw |
916 | n %r8,BASED(cleanup_idle_wait) # clear irq & wait state bits | 916 | n %r8,BASED(.Lcleanup_idle_wait) # clear irq & wait state bits |
917 | l %r9,24(%r11) # return from psw_idle | 917 | l %r9,24(%r11) # return from psw_idle |
918 | br %r14 | 918 | br %r14 |
919 | cleanup_idle_insn: | 919 | .Lcleanup_idle_insn: |
920 | .long psw_idle_lpsw + 0x80000000 | 920 | .long .Lpsw_idle_lpsw + 0x80000000 |
921 | cleanup_idle_wait: | 921 | .Lcleanup_idle_wait: |
922 | .long 0xfcfdffff | 922 | .long 0xfcfdffff |
923 | 923 | ||
924 | /* | 924 | /* |
@@ -933,30 +933,30 @@ cleanup_idle_wait: | |||
933 | /* | 933 | /* |
934 | * Symbol constants | 934 | * Symbol constants |
935 | */ | 935 | */ |
936 | .Ldo_machine_check: .long s390_do_machine_check | 936 | .Lc_do_machine_check: .long s390_do_machine_check |
937 | .Lhandle_mcck: .long s390_handle_mcck | 937 | .Lc_handle_mcck: .long s390_handle_mcck |
938 | .Ldo_IRQ: .long do_IRQ | 938 | .Lc_do_IRQ: .long do_IRQ |
939 | .Ldo_signal: .long do_signal | 939 | .Lc_do_signal: .long do_signal |
940 | .Ldo_notify_resume: .long do_notify_resume | 940 | .Lc_do_notify_resume: .long do_notify_resume |
941 | .Ldo_per_trap: .long do_per_trap | 941 | .Lc_do_per_trap: .long do_per_trap |
942 | .Ljump_table: .long pgm_check_table | 942 | .Lc_jump_table: .long pgm_check_table |
943 | .Lschedule: .long schedule | 943 | .Lc_schedule: .long schedule |
944 | #ifdef CONFIG_PREEMPT | 944 | #ifdef CONFIG_PREEMPT |
945 | .Lpreempt_irq: .long preempt_schedule_irq | 945 | .Lc_preempt_irq: .long preempt_schedule_irq |
946 | #endif | 946 | #endif |
947 | .Ltrace_enter: .long do_syscall_trace_enter | 947 | .Lc_trace_enter: .long do_syscall_trace_enter |
948 | .Ltrace_exit: .long do_syscall_trace_exit | 948 | .Lc_trace_exit: .long do_syscall_trace_exit |
949 | .Lschedule_tail: .long schedule_tail | 949 | .Lc_schedule_tail: .long schedule_tail |
950 | .Lsysc_per: .long sysc_per + 0x80000000 | 950 | .Lc_sysc_per: .long .Lsysc_per + 0x80000000 |
951 | #ifdef CONFIG_TRACE_IRQFLAGS | 951 | #ifdef CONFIG_TRACE_IRQFLAGS |
952 | .Lhardirqs_on: .long trace_hardirqs_on_caller | 952 | .Lc_hardirqs_on: .long trace_hardirqs_on_caller |
953 | .Lhardirqs_off: .long trace_hardirqs_off_caller | 953 | .Lc_hardirqs_off: .long trace_hardirqs_off_caller |
954 | #endif | 954 | #endif |
955 | #ifdef CONFIG_LOCKDEP | 955 | #ifdef CONFIG_LOCKDEP |
956 | .Llockdep_sys_exit: .long lockdep_sys_exit | 956 | .Lc_lockdep_sys_exit: .long lockdep_sys_exit |
957 | #endif | 957 | #endif |
958 | .Lcritical_start: .long __critical_start + 0x80000000 | 958 | .Lc_critical_start: .long .L__critical_start + 0x80000000 |
959 | .Lcritical_length: .long __critical_end - __critical_start | 959 | .Lc_critical_length: .long .L__critical_end - .L__critical_start |
960 | 960 | ||
961 | .section .rodata, "a" | 961 | .section .rodata, "a" |
962 | #define SYSCALL(esa,esame,emu) .long esa | 962 | #define SYSCALL(esa,esame,emu) .long esa |
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 0554b9771c9f..8e61393c8275 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -74,4 +74,6 @@ struct old_sigaction; | |||
74 | long sys_s390_personality(unsigned int personality); | 74 | long sys_s390_personality(unsigned int personality); |
75 | long sys_s390_runtime_instr(int command, int signum); | 75 | long sys_s390_runtime_instr(int command, int signum); |
76 | 76 | ||
77 | long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); | ||
78 | long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); | ||
77 | #endif /* _ENTRY_H */ | 79 | #endif /* _ENTRY_H */ |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 7b2e03afd017..c329446a951d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -91,7 +91,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
91 | .if \reason==1 | 91 | .if \reason==1 |
92 | # Some program interrupts are suppressing (e.g. protection). | 92 | # Some program interrupts are suppressing (e.g. protection). |
93 | # We must also check the instruction after SIE in that case. | 93 | # We must also check the instruction after SIE in that case. |
94 | # do_protection_exception will rewind to rewind_pad | 94 | # do_protection_exception will rewind to .Lrewind_pad |
95 | jh .+42 | 95 | jh .+42 |
96 | .else | 96 | .else |
97 | jhe .+42 | 97 | jhe .+42 |
@@ -192,7 +192,7 @@ ENTRY(__switch_to) | |||
192 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 192 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
193 | br %r14 | 193 | br %r14 |
194 | 194 | ||
195 | __critical_start: | 195 | .L__critical_start: |
196 | /* | 196 | /* |
197 | * SVC interrupt handler routine. System calls are synchronous events and | 197 | * SVC interrupt handler routine. System calls are synchronous events and |
198 | * are executed with interrupts enabled. | 198 | * are executed with interrupts enabled. |
@@ -200,15 +200,15 @@ __critical_start: | |||
200 | 200 | ||
201 | ENTRY(system_call) | 201 | ENTRY(system_call) |
202 | stpt __LC_SYNC_ENTER_TIMER | 202 | stpt __LC_SYNC_ENTER_TIMER |
203 | sysc_stmg: | 203 | .Lsysc_stmg: |
204 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC | 204 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
205 | lg %r10,__LC_LAST_BREAK | 205 | lg %r10,__LC_LAST_BREAK |
206 | lg %r12,__LC_THREAD_INFO | 206 | lg %r12,__LC_THREAD_INFO |
207 | lghi %r14,_PIF_SYSCALL | 207 | lghi %r14,_PIF_SYSCALL |
208 | sysc_per: | 208 | .Lsysc_per: |
209 | lg %r15,__LC_KERNEL_STACK | 209 | lg %r15,__LC_KERNEL_STACK |
210 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | 210 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs |
211 | sysc_vtime: | 211 | .Lsysc_vtime: |
212 | UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER | 212 | UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER |
213 | LAST_BREAK %r13 | 213 | LAST_BREAK %r13 |
214 | stmg %r0,%r7,__PT_R0(%r11) | 214 | stmg %r0,%r7,__PT_R0(%r11) |
@@ -216,39 +216,39 @@ sysc_vtime: | |||
216 | mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW | 216 | mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW |
217 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC | 217 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
218 | stg %r14,__PT_FLAGS(%r11) | 218 | stg %r14,__PT_FLAGS(%r11) |
219 | sysc_do_svc: | 219 | .Lsysc_do_svc: |
220 | lg %r10,__TI_sysc_table(%r12) # address of system call table | 220 | lg %r10,__TI_sysc_table(%r12) # address of system call table |
221 | llgh %r8,__PT_INT_CODE+2(%r11) | 221 | llgh %r8,__PT_INT_CODE+2(%r11) |
222 | slag %r8,%r8,2 # shift and test for svc 0 | 222 | slag %r8,%r8,2 # shift and test for svc 0 |
223 | jnz sysc_nr_ok | 223 | jnz .Lsysc_nr_ok |
224 | # svc 0: system call number in %r1 | 224 | # svc 0: system call number in %r1 |
225 | llgfr %r1,%r1 # clear high word in r1 | 225 | llgfr %r1,%r1 # clear high word in r1 |
226 | cghi %r1,NR_syscalls | 226 | cghi %r1,NR_syscalls |
227 | jnl sysc_nr_ok | 227 | jnl .Lsysc_nr_ok |
228 | sth %r1,__PT_INT_CODE+2(%r11) | 228 | sth %r1,__PT_INT_CODE+2(%r11) |
229 | slag %r8,%r1,2 | 229 | slag %r8,%r1,2 |
230 | sysc_nr_ok: | 230 | .Lsysc_nr_ok: |
231 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 231 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
232 | stg %r2,__PT_ORIG_GPR2(%r11) | 232 | stg %r2,__PT_ORIG_GPR2(%r11) |
233 | stg %r7,STACK_FRAME_OVERHEAD(%r15) | 233 | stg %r7,STACK_FRAME_OVERHEAD(%r15) |
234 | lgf %r9,0(%r8,%r10) # get system call add. | 234 | lgf %r9,0(%r8,%r10) # get system call add. |
235 | tm __TI_flags+7(%r12),_TIF_TRACE | 235 | tm __TI_flags+7(%r12),_TIF_TRACE |
236 | jnz sysc_tracesys | 236 | jnz .Lsysc_tracesys |
237 | basr %r14,%r9 # call sys_xxxx | 237 | basr %r14,%r9 # call sys_xxxx |
238 | stg %r2,__PT_R2(%r11) # store return value | 238 | stg %r2,__PT_R2(%r11) # store return value |
239 | 239 | ||
240 | sysc_return: | 240 | .Lsysc_return: |
241 | LOCKDEP_SYS_EXIT | 241 | LOCKDEP_SYS_EXIT |
242 | sysc_tif: | 242 | .Lsysc_tif: |
243 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 243 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
244 | jno sysc_restore | 244 | jno .Lsysc_restore |
245 | tm __PT_FLAGS+7(%r11),_PIF_WORK | 245 | tm __PT_FLAGS+7(%r11),_PIF_WORK |
246 | jnz sysc_work | 246 | jnz .Lsysc_work |
247 | tm __TI_flags+7(%r12),_TIF_WORK | 247 | tm __TI_flags+7(%r12),_TIF_WORK |
248 | jnz sysc_work # check for work | 248 | jnz .Lsysc_work # check for work |
249 | tm __LC_CPU_FLAGS+7,_CIF_WORK | 249 | tm __LC_CPU_FLAGS+7,_CIF_WORK |
250 | jnz sysc_work | 250 | jnz .Lsysc_work |
251 | sysc_restore: | 251 | .Lsysc_restore: |
252 | lg %r14,__LC_VDSO_PER_CPU | 252 | lg %r14,__LC_VDSO_PER_CPU |
253 | lmg %r0,%r10,__PT_R0(%r11) | 253 | lmg %r0,%r10,__PT_R0(%r11) |
254 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | 254 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) |
@@ -256,101 +256,101 @@ sysc_restore: | |||
256 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | 256 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER |
257 | lmg %r11,%r15,__PT_R11(%r11) | 257 | lmg %r11,%r15,__PT_R11(%r11) |
258 | lpswe __LC_RETURN_PSW | 258 | lpswe __LC_RETURN_PSW |
259 | sysc_done: | 259 | .Lsysc_done: |
260 | 260 | ||
261 | # | 261 | # |
262 | # One of the work bits is on. Find out which one. | 262 | # One of the work bits is on. Find out which one. |
263 | # | 263 | # |
264 | sysc_work: | 264 | .Lsysc_work: |
265 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 265 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
266 | jo sysc_mcck_pending | 266 | jo .Lsysc_mcck_pending |
267 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 267 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
268 | jo sysc_reschedule | 268 | jo .Lsysc_reschedule |
269 | #ifdef CONFIG_UPROBES | 269 | #ifdef CONFIG_UPROBES |
270 | tm __TI_flags+7(%r12),_TIF_UPROBE | 270 | tm __TI_flags+7(%r12),_TIF_UPROBE |
271 | jo sysc_uprobe_notify | 271 | jo .Lsysc_uprobe_notify |
272 | #endif | 272 | #endif |
273 | tm __PT_FLAGS+7(%r11),_PIF_PER_TRAP | 273 | tm __PT_FLAGS+7(%r11),_PIF_PER_TRAP |
274 | jo sysc_singlestep | 274 | jo .Lsysc_singlestep |
275 | tm __TI_flags+7(%r12),_TIF_SIGPENDING | 275 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
276 | jo sysc_sigpending | 276 | jo .Lsysc_sigpending |
277 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME | 277 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
278 | jo sysc_notify_resume | 278 | jo .Lsysc_notify_resume |
279 | tm __LC_CPU_FLAGS+7,_CIF_ASCE | 279 | tm __LC_CPU_FLAGS+7,_CIF_ASCE |
280 | jo sysc_uaccess | 280 | jo .Lsysc_uaccess |
281 | j sysc_return # beware of critical section cleanup | 281 | j .Lsysc_return # beware of critical section cleanup |
282 | 282 | ||
283 | # | 283 | # |
284 | # _TIF_NEED_RESCHED is set, call schedule | 284 | # _TIF_NEED_RESCHED is set, call schedule |
285 | # | 285 | # |
286 | sysc_reschedule: | 286 | .Lsysc_reschedule: |
287 | larl %r14,sysc_return | 287 | larl %r14,.Lsysc_return |
288 | jg schedule | 288 | jg schedule |
289 | 289 | ||
290 | # | 290 | # |
291 | # _CIF_MCCK_PENDING is set, call handler | 291 | # _CIF_MCCK_PENDING is set, call handler |
292 | # | 292 | # |
293 | sysc_mcck_pending: | 293 | .Lsysc_mcck_pending: |
294 | larl %r14,sysc_return | 294 | larl %r14,.Lsysc_return |
295 | jg s390_handle_mcck # TIF bit will be cleared by handler | 295 | jg s390_handle_mcck # TIF bit will be cleared by handler |
296 | 296 | ||
297 | # | 297 | # |
298 | # _CIF_ASCE is set, load user space asce | 298 | # _CIF_ASCE is set, load user space asce |
299 | # | 299 | # |
300 | sysc_uaccess: | 300 | .Lsysc_uaccess: |
301 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE | 301 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE |
302 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 302 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
303 | j sysc_return | 303 | j .Lsysc_return |
304 | 304 | ||
305 | # | 305 | # |
306 | # _TIF_SIGPENDING is set, call do_signal | 306 | # _TIF_SIGPENDING is set, call do_signal |
307 | # | 307 | # |
308 | sysc_sigpending: | 308 | .Lsysc_sigpending: |
309 | lgr %r2,%r11 # pass pointer to pt_regs | 309 | lgr %r2,%r11 # pass pointer to pt_regs |
310 | brasl %r14,do_signal | 310 | brasl %r14,do_signal |
311 | tm __PT_FLAGS+7(%r11),_PIF_SYSCALL | 311 | tm __PT_FLAGS+7(%r11),_PIF_SYSCALL |
312 | jno sysc_return | 312 | jno .Lsysc_return |
313 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments | 313 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments |
314 | lg %r10,__TI_sysc_table(%r12) # address of system call table | 314 | lg %r10,__TI_sysc_table(%r12) # address of system call table |
315 | lghi %r8,0 # svc 0 returns -ENOSYS | 315 | lghi %r8,0 # svc 0 returns -ENOSYS |
316 | llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number | 316 | llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number |
317 | cghi %r1,NR_syscalls | 317 | cghi %r1,NR_syscalls |
318 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 318 | jnl .Lsysc_nr_ok # invalid svc number -> do svc 0 |
319 | slag %r8,%r1,2 | 319 | slag %r8,%r1,2 |
320 | j sysc_nr_ok # restart svc | 320 | j .Lsysc_nr_ok # restart svc |
321 | 321 | ||
322 | # | 322 | # |
323 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 323 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
324 | # | 324 | # |
325 | sysc_notify_resume: | 325 | .Lsysc_notify_resume: |
326 | lgr %r2,%r11 # pass pointer to pt_regs | 326 | lgr %r2,%r11 # pass pointer to pt_regs |
327 | larl %r14,sysc_return | 327 | larl %r14,.Lsysc_return |
328 | jg do_notify_resume | 328 | jg do_notify_resume |
329 | 329 | ||
330 | # | 330 | # |
331 | # _TIF_UPROBE is set, call uprobe_notify_resume | 331 | # _TIF_UPROBE is set, call uprobe_notify_resume |
332 | # | 332 | # |
333 | #ifdef CONFIG_UPROBES | 333 | #ifdef CONFIG_UPROBES |
334 | sysc_uprobe_notify: | 334 | .Lsysc_uprobe_notify: |
335 | lgr %r2,%r11 # pass pointer to pt_regs | 335 | lgr %r2,%r11 # pass pointer to pt_regs |
336 | larl %r14,sysc_return | 336 | larl %r14,.Lsysc_return |
337 | jg uprobe_notify_resume | 337 | jg uprobe_notify_resume |
338 | #endif | 338 | #endif |
339 | 339 | ||
340 | # | 340 | # |
341 | # _PIF_PER_TRAP is set, call do_per_trap | 341 | # _PIF_PER_TRAP is set, call do_per_trap |
342 | # | 342 | # |
343 | sysc_singlestep: | 343 | .Lsysc_singlestep: |
344 | ni __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP | 344 | ni __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP |
345 | lgr %r2,%r11 # pass pointer to pt_regs | 345 | lgr %r2,%r11 # pass pointer to pt_regs |
346 | larl %r14,sysc_return | 346 | larl %r14,.Lsysc_return |
347 | jg do_per_trap | 347 | jg do_per_trap |
348 | 348 | ||
349 | # | 349 | # |
350 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before | 350 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
351 | # and after the system call | 351 | # and after the system call |
352 | # | 352 | # |
353 | sysc_tracesys: | 353 | .Lsysc_tracesys: |
354 | lgr %r2,%r11 # pass pointer to pt_regs | 354 | lgr %r2,%r11 # pass pointer to pt_regs |
355 | la %r3,0 | 355 | la %r3,0 |
356 | llgh %r0,__PT_INT_CODE+2(%r11) | 356 | llgh %r0,__PT_INT_CODE+2(%r11) |
@@ -358,20 +358,20 @@ sysc_tracesys: | |||
358 | brasl %r14,do_syscall_trace_enter | 358 | brasl %r14,do_syscall_trace_enter |
359 | lghi %r0,NR_syscalls | 359 | lghi %r0,NR_syscalls |
360 | clgr %r0,%r2 | 360 | clgr %r0,%r2 |
361 | jnh sysc_tracenogo | 361 | jnh .Lsysc_tracenogo |
362 | sllg %r8,%r2,2 | 362 | sllg %r8,%r2,2 |
363 | lgf %r9,0(%r8,%r10) | 363 | lgf %r9,0(%r8,%r10) |
364 | sysc_tracego: | 364 | .Lsysc_tracego: |
365 | lmg %r3,%r7,__PT_R3(%r11) | 365 | lmg %r3,%r7,__PT_R3(%r11) |
366 | stg %r7,STACK_FRAME_OVERHEAD(%r15) | 366 | stg %r7,STACK_FRAME_OVERHEAD(%r15) |
367 | lg %r2,__PT_ORIG_GPR2(%r11) | 367 | lg %r2,__PT_ORIG_GPR2(%r11) |
368 | basr %r14,%r9 # call sys_xxx | 368 | basr %r14,%r9 # call sys_xxx |
369 | stg %r2,__PT_R2(%r11) # store return value | 369 | stg %r2,__PT_R2(%r11) # store return value |
370 | sysc_tracenogo: | 370 | .Lsysc_tracenogo: |
371 | tm __TI_flags+7(%r12),_TIF_TRACE | 371 | tm __TI_flags+7(%r12),_TIF_TRACE |
372 | jz sysc_return | 372 | jz .Lsysc_return |
373 | lgr %r2,%r11 # pass pointer to pt_regs | 373 | lgr %r2,%r11 # pass pointer to pt_regs |
374 | larl %r14,sysc_return | 374 | larl %r14,.Lsysc_return |
375 | jg do_syscall_trace_exit | 375 | jg do_syscall_trace_exit |
376 | 376 | ||
377 | # | 377 | # |
@@ -384,13 +384,13 @@ ENTRY(ret_from_fork) | |||
384 | TRACE_IRQS_ON | 384 | TRACE_IRQS_ON |
385 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 385 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
386 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | 386 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
387 | jne sysc_tracenogo | 387 | jne .Lsysc_tracenogo |
388 | # it's a kernel thread | 388 | # it's a kernel thread |
389 | lmg %r9,%r10,__PT_R9(%r11) # load gprs | 389 | lmg %r9,%r10,__PT_R9(%r11) # load gprs |
390 | ENTRY(kernel_thread_starter) | 390 | ENTRY(kernel_thread_starter) |
391 | la %r2,0(%r10) | 391 | la %r2,0(%r10) |
392 | basr %r14,%r9 | 392 | basr %r14,%r9 |
393 | j sysc_tracenogo | 393 | j .Lsysc_tracenogo |
394 | 394 | ||
395 | /* | 395 | /* |
396 | * Program check handler routine | 396 | * Program check handler routine |
@@ -409,7 +409,7 @@ ENTRY(pgm_check_handler) | |||
409 | tmhh %r8,0x4000 # PER bit set in old PSW ? | 409 | tmhh %r8,0x4000 # PER bit set in old PSW ? |
410 | jnz 0f # -> enabled, can't be a double fault | 410 | jnz 0f # -> enabled, can't be a double fault |
411 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 411 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
412 | jnz pgm_svcper # -> single stepped svc | 412 | jnz .Lpgm_svcper # -> single stepped svc |
413 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC | 413 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
414 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 414 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
415 | j 2f | 415 | j 2f |
@@ -432,7 +432,7 @@ ENTRY(pgm_check_handler) | |||
432 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 432 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
433 | jz 0f | 433 | jz 0f |
434 | tmhh %r8,0x0001 # kernel per event ? | 434 | tmhh %r8,0x0001 # kernel per event ? |
435 | jz pgm_kprobe | 435 | jz .Lpgm_kprobe |
436 | oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP | 436 | oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP |
437 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS | 437 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS |
438 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE | 438 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE |
@@ -443,31 +443,31 @@ ENTRY(pgm_check_handler) | |||
443 | llgh %r10,__PT_INT_CODE+2(%r11) | 443 | llgh %r10,__PT_INT_CODE+2(%r11) |
444 | nill %r10,0x007f | 444 | nill %r10,0x007f |
445 | sll %r10,2 | 445 | sll %r10,2 |
446 | je sysc_return | 446 | je .Lsysc_return |
447 | lgf %r1,0(%r10,%r1) # load address of handler routine | 447 | lgf %r1,0(%r10,%r1) # load address of handler routine |
448 | lgr %r2,%r11 # pass pointer to pt_regs | 448 | lgr %r2,%r11 # pass pointer to pt_regs |
449 | basr %r14,%r1 # branch to interrupt-handler | 449 | basr %r14,%r1 # branch to interrupt-handler |
450 | j sysc_return | 450 | j .Lsysc_return |
451 | 451 | ||
452 | # | 452 | # |
453 | # PER event in supervisor state, must be kprobes | 453 | # PER event in supervisor state, must be kprobes |
454 | # | 454 | # |
455 | pgm_kprobe: | 455 | .Lpgm_kprobe: |
456 | REENABLE_IRQS | 456 | REENABLE_IRQS |
457 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 457 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
458 | lgr %r2,%r11 # pass pointer to pt_regs | 458 | lgr %r2,%r11 # pass pointer to pt_regs |
459 | brasl %r14,do_per_trap | 459 | brasl %r14,do_per_trap |
460 | j sysc_return | 460 | j .Lsysc_return |
461 | 461 | ||
462 | # | 462 | # |
463 | # single stepped system call | 463 | # single stepped system call |
464 | # | 464 | # |
465 | pgm_svcper: | 465 | .Lpgm_svcper: |
466 | mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW | 466 | mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW |
467 | larl %r14,sysc_per | 467 | larl %r14,.Lsysc_per |
468 | stg %r14,__LC_RETURN_PSW+8 | 468 | stg %r14,__LC_RETURN_PSW+8 |
469 | lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP | 469 | lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP |
470 | lpswe __LC_RETURN_PSW # branch to sysc_per and enable irqs | 470 | lpswe __LC_RETURN_PSW # branch to .Lsysc_per and enable irqs |
471 | 471 | ||
472 | /* | 472 | /* |
473 | * IO interrupt handler routine | 473 | * IO interrupt handler routine |
@@ -483,10 +483,10 @@ ENTRY(io_int_handler) | |||
483 | HANDLE_SIE_INTERCEPT %r14,2 | 483 | HANDLE_SIE_INTERCEPT %r14,2 |
484 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 484 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
485 | tmhh %r8,0x0001 # interrupting from user? | 485 | tmhh %r8,0x0001 # interrupting from user? |
486 | jz io_skip | 486 | jz .Lio_skip |
487 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER | 487 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
488 | LAST_BREAK %r14 | 488 | LAST_BREAK %r14 |
489 | io_skip: | 489 | .Lio_skip: |
490 | stmg %r0,%r7,__PT_R0(%r11) | 490 | stmg %r0,%r7,__PT_R0(%r11) |
491 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 491 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
492 | stmg %r8,%r9,__PT_PSW(%r11) | 492 | stmg %r8,%r9,__PT_PSW(%r11) |
@@ -494,29 +494,29 @@ io_skip: | |||
494 | xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) | 494 | xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) |
495 | TRACE_IRQS_OFF | 495 | TRACE_IRQS_OFF |
496 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 496 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
497 | io_loop: | 497 | .Lio_loop: |
498 | lgr %r2,%r11 # pass pointer to pt_regs | 498 | lgr %r2,%r11 # pass pointer to pt_regs |
499 | lghi %r3,IO_INTERRUPT | 499 | lghi %r3,IO_INTERRUPT |
500 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? | 500 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? |
501 | jz io_call | 501 | jz .Lio_call |
502 | lghi %r3,THIN_INTERRUPT | 502 | lghi %r3,THIN_INTERRUPT |
503 | io_call: | 503 | .Lio_call: |
504 | brasl %r14,do_IRQ | 504 | brasl %r14,do_IRQ |
505 | tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR | 505 | tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR |
506 | jz io_return | 506 | jz .Lio_return |
507 | tpi 0 | 507 | tpi 0 |
508 | jz io_return | 508 | jz .Lio_return |
509 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | 509 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID |
510 | j io_loop | 510 | j .Lio_loop |
511 | io_return: | 511 | .Lio_return: |
512 | LOCKDEP_SYS_EXIT | 512 | LOCKDEP_SYS_EXIT |
513 | TRACE_IRQS_ON | 513 | TRACE_IRQS_ON |
514 | io_tif: | 514 | .Lio_tif: |
515 | tm __TI_flags+7(%r12),_TIF_WORK | 515 | tm __TI_flags+7(%r12),_TIF_WORK |
516 | jnz io_work # there is work to do (signals etc.) | 516 | jnz .Lio_work # there is work to do (signals etc.) |
517 | tm __LC_CPU_FLAGS+7,_CIF_WORK | 517 | tm __LC_CPU_FLAGS+7,_CIF_WORK |
518 | jnz io_work | 518 | jnz .Lio_work |
519 | io_restore: | 519 | .Lio_restore: |
520 | lg %r14,__LC_VDSO_PER_CPU | 520 | lg %r14,__LC_VDSO_PER_CPU |
521 | lmg %r0,%r10,__PT_R0(%r11) | 521 | lmg %r0,%r10,__PT_R0(%r11) |
522 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | 522 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) |
@@ -524,7 +524,7 @@ io_restore: | |||
524 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | 524 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER |
525 | lmg %r11,%r15,__PT_R11(%r11) | 525 | lmg %r11,%r15,__PT_R11(%r11) |
526 | lpswe __LC_RETURN_PSW | 526 | lpswe __LC_RETURN_PSW |
527 | io_done: | 527 | .Lio_done: |
528 | 528 | ||
529 | # | 529 | # |
530 | # There is work todo, find out in which context we have been interrupted: | 530 | # There is work todo, find out in which context we have been interrupted: |
@@ -535,15 +535,15 @@ io_done: | |||
535 | # the preemption counter and if it is zero call preempt_schedule_irq | 535 | # the preemption counter and if it is zero call preempt_schedule_irq |
536 | # Before any work can be done, a switch to the kernel stack is required. | 536 | # Before any work can be done, a switch to the kernel stack is required. |
537 | # | 537 | # |
538 | io_work: | 538 | .Lio_work: |
539 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 539 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
540 | jo io_work_user # yes -> do resched & signal | 540 | jo .Lio_work_user # yes -> do resched & signal |
541 | #ifdef CONFIG_PREEMPT | 541 | #ifdef CONFIG_PREEMPT |
542 | # check for preemptive scheduling | 542 | # check for preemptive scheduling |
543 | icm %r0,15,__TI_precount(%r12) | 543 | icm %r0,15,__TI_precount(%r12) |
544 | jnz io_restore # preemption is disabled | 544 | jnz .Lio_restore # preemption is disabled |
545 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 545 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
546 | jno io_restore | 546 | jno .Lio_restore |
547 | # switch to kernel stack | 547 | # switch to kernel stack |
548 | lg %r1,__PT_R15(%r11) | 548 | lg %r1,__PT_R15(%r11) |
549 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 549 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
@@ -551,19 +551,19 @@ io_work: | |||
551 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 551 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
552 | la %r11,STACK_FRAME_OVERHEAD(%r1) | 552 | la %r11,STACK_FRAME_OVERHEAD(%r1) |
553 | lgr %r15,%r1 | 553 | lgr %r15,%r1 |
554 | # TRACE_IRQS_ON already done at io_return, call | 554 | # TRACE_IRQS_ON already done at .Lio_return, call |
555 | # TRACE_IRQS_OFF to keep things symmetrical | 555 | # TRACE_IRQS_OFF to keep things symmetrical |
556 | TRACE_IRQS_OFF | 556 | TRACE_IRQS_OFF |
557 | brasl %r14,preempt_schedule_irq | 557 | brasl %r14,preempt_schedule_irq |
558 | j io_return | 558 | j .Lio_return |
559 | #else | 559 | #else |
560 | j io_restore | 560 | j .Lio_restore |
561 | #endif | 561 | #endif |
562 | 562 | ||
563 | # | 563 | # |
564 | # Need to do work before returning to userspace, switch to kernel stack | 564 | # Need to do work before returning to userspace, switch to kernel stack |
565 | # | 565 | # |
566 | io_work_user: | 566 | .Lio_work_user: |
567 | lg %r1,__LC_KERNEL_STACK | 567 | lg %r1,__LC_KERNEL_STACK |
568 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 568 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
569 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 569 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
@@ -573,70 +573,70 @@ io_work_user: | |||
573 | # | 573 | # |
574 | # One of the work bits is on. Find out which one. | 574 | # One of the work bits is on. Find out which one. |
575 | # | 575 | # |
576 | io_work_tif: | 576 | .Lio_work_tif: |
577 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 577 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
578 | jo io_mcck_pending | 578 | jo .Lio_mcck_pending |
579 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 579 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
580 | jo io_reschedule | 580 | jo .Lio_reschedule |
581 | tm __TI_flags+7(%r12),_TIF_SIGPENDING | 581 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
582 | jo io_sigpending | 582 | jo .Lio_sigpending |
583 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME | 583 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
584 | jo io_notify_resume | 584 | jo .Lio_notify_resume |
585 | tm __LC_CPU_FLAGS+7,_CIF_ASCE | 585 | tm __LC_CPU_FLAGS+7,_CIF_ASCE |
586 | jo io_uaccess | 586 | jo .Lio_uaccess |
587 | j io_return # beware of critical section cleanup | 587 | j .Lio_return # beware of critical section cleanup |
588 | 588 | ||
589 | # | 589 | # |
590 | # _CIF_MCCK_PENDING is set, call handler | 590 | # _CIF_MCCK_PENDING is set, call handler |
591 | # | 591 | # |
592 | io_mcck_pending: | 592 | .Lio_mcck_pending: |
593 | # TRACE_IRQS_ON already done at io_return | 593 | # TRACE_IRQS_ON already done at .Lio_return |
594 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler | 594 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler |
595 | TRACE_IRQS_OFF | 595 | TRACE_IRQS_OFF |
596 | j io_return | 596 | j .Lio_return |
597 | 597 | ||
598 | # | 598 | # |
599 | # _CIF_ASCE is set, load user space asce | 599 | # _CIF_ASCE is set, load user space asce |
600 | # | 600 | # |
601 | io_uaccess: | 601 | .Lio_uaccess: |
602 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE | 602 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE |
603 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 603 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
604 | j io_return | 604 | j .Lio_return |
605 | 605 | ||
606 | # | 606 | # |
607 | # _TIF_NEED_RESCHED is set, call schedule | 607 | # _TIF_NEED_RESCHED is set, call schedule |
608 | # | 608 | # |
609 | io_reschedule: | 609 | .Lio_reschedule: |
610 | # TRACE_IRQS_ON already done at io_return | 610 | # TRACE_IRQS_ON already done at .Lio_return |
611 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 611 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
612 | brasl %r14,schedule # call scheduler | 612 | brasl %r14,schedule # call scheduler |
613 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 613 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
614 | TRACE_IRQS_OFF | 614 | TRACE_IRQS_OFF |
615 | j io_return | 615 | j .Lio_return |
616 | 616 | ||
617 | # | 617 | # |
618 | # _TIF_SIGPENDING or is set, call do_signal | 618 | # _TIF_SIGPENDING or is set, call do_signal |
619 | # | 619 | # |
620 | io_sigpending: | 620 | .Lio_sigpending: |
621 | # TRACE_IRQS_ON already done at io_return | 621 | # TRACE_IRQS_ON already done at .Lio_return |
622 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 622 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
623 | lgr %r2,%r11 # pass pointer to pt_regs | 623 | lgr %r2,%r11 # pass pointer to pt_regs |
624 | brasl %r14,do_signal | 624 | brasl %r14,do_signal |
625 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 625 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
626 | TRACE_IRQS_OFF | 626 | TRACE_IRQS_OFF |
627 | j io_return | 627 | j .Lio_return |
628 | 628 | ||
629 | # | 629 | # |
630 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume | 630 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume |
631 | # | 631 | # |
632 | io_notify_resume: | 632 | .Lio_notify_resume: |
633 | # TRACE_IRQS_ON already done at io_return | 633 | # TRACE_IRQS_ON already done at .Lio_return |
634 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 634 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
635 | lgr %r2,%r11 # pass pointer to pt_regs | 635 | lgr %r2,%r11 # pass pointer to pt_regs |
636 | brasl %r14,do_notify_resume | 636 | brasl %r14,do_notify_resume |
637 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 637 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
638 | TRACE_IRQS_OFF | 638 | TRACE_IRQS_OFF |
639 | j io_return | 639 | j .Lio_return |
640 | 640 | ||
641 | /* | 641 | /* |
642 | * External interrupt handler routine | 642 | * External interrupt handler routine |
@@ -652,10 +652,10 @@ ENTRY(ext_int_handler) | |||
652 | HANDLE_SIE_INTERCEPT %r14,3 | 652 | HANDLE_SIE_INTERCEPT %r14,3 |
653 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 653 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
654 | tmhh %r8,0x0001 # interrupting from user ? | 654 | tmhh %r8,0x0001 # interrupting from user ? |
655 | jz ext_skip | 655 | jz .Lext_skip |
656 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER | 656 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
657 | LAST_BREAK %r14 | 657 | LAST_BREAK %r14 |
658 | ext_skip: | 658 | .Lext_skip: |
659 | stmg %r0,%r7,__PT_R0(%r11) | 659 | stmg %r0,%r7,__PT_R0(%r11) |
660 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 660 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
661 | stmg %r8,%r9,__PT_PSW(%r11) | 661 | stmg %r8,%r9,__PT_PSW(%r11) |
@@ -669,23 +669,23 @@ ext_skip: | |||
669 | lgr %r2,%r11 # pass pointer to pt_regs | 669 | lgr %r2,%r11 # pass pointer to pt_regs |
670 | lghi %r3,EXT_INTERRUPT | 670 | lghi %r3,EXT_INTERRUPT |
671 | brasl %r14,do_IRQ | 671 | brasl %r14,do_IRQ |
672 | j io_return | 672 | j .Lio_return |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * Load idle PSW. The second "half" of this function is in cleanup_idle. | 675 | * Load idle PSW. The second "half" of this function is in .Lcleanup_idle. |
676 | */ | 676 | */ |
677 | ENTRY(psw_idle) | 677 | ENTRY(psw_idle) |
678 | stg %r3,__SF_EMPTY(%r15) | 678 | stg %r3,__SF_EMPTY(%r15) |
679 | larl %r1,psw_idle_lpsw+4 | 679 | larl %r1,.Lpsw_idle_lpsw+4 |
680 | stg %r1,__SF_EMPTY+8(%r15) | 680 | stg %r1,__SF_EMPTY+8(%r15) |
681 | STCK __CLOCK_IDLE_ENTER(%r2) | 681 | STCK __CLOCK_IDLE_ENTER(%r2) |
682 | stpt __TIMER_IDLE_ENTER(%r2) | 682 | stpt __TIMER_IDLE_ENTER(%r2) |
683 | psw_idle_lpsw: | 683 | .Lpsw_idle_lpsw: |
684 | lpswe __SF_EMPTY(%r15) | 684 | lpswe __SF_EMPTY(%r15) |
685 | br %r14 | 685 | br %r14 |
686 | psw_idle_end: | 686 | .Lpsw_idle_end: |
687 | 687 | ||
688 | __critical_end: | 688 | .L__critical_end: |
689 | 689 | ||
690 | /* | 690 | /* |
691 | * Machine check handler routines | 691 | * Machine check handler routines |
@@ -701,7 +701,7 @@ ENTRY(mcck_int_handler) | |||
701 | lmg %r8,%r9,__LC_MCK_OLD_PSW | 701 | lmg %r8,%r9,__LC_MCK_OLD_PSW |
702 | HANDLE_SIE_INTERCEPT %r14,4 | 702 | HANDLE_SIE_INTERCEPT %r14,4 |
703 | tm __LC_MCCK_CODE,0x80 # system damage? | 703 | tm __LC_MCCK_CODE,0x80 # system damage? |
704 | jo mcck_panic # yes -> rest of mcck code invalid | 704 | jo .Lmcck_panic # yes -> rest of mcck code invalid |
705 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA | 705 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA |
706 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 706 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
707 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 707 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
@@ -719,13 +719,13 @@ ENTRY(mcck_int_handler) | |||
719 | 2: spt 0(%r14) | 719 | 2: spt 0(%r14) |
720 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 720 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
721 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 721 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
722 | jno mcck_panic # no -> skip cleanup critical | 722 | jno .Lmcck_panic # no -> skip cleanup critical |
723 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_PANIC_STACK,PAGE_SHIFT | 723 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_PANIC_STACK,PAGE_SHIFT |
724 | tm %r8,0x0001 # interrupting from user ? | 724 | tm %r8,0x0001 # interrupting from user ? |
725 | jz mcck_skip | 725 | jz .Lmcck_skip |
726 | UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER | 726 | UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER |
727 | LAST_BREAK %r14 | 727 | LAST_BREAK %r14 |
728 | mcck_skip: | 728 | .Lmcck_skip: |
729 | lghi %r14,__LC_GPREGS_SAVE_AREA+64 | 729 | lghi %r14,__LC_GPREGS_SAVE_AREA+64 |
730 | stmg %r0,%r7,__PT_R0(%r11) | 730 | stmg %r0,%r7,__PT_R0(%r11) |
731 | mvc __PT_R8(64,%r11),0(%r14) | 731 | mvc __PT_R8(64,%r11),0(%r14) |
@@ -735,7 +735,7 @@ mcck_skip: | |||
735 | lgr %r2,%r11 # pass pointer to pt_regs | 735 | lgr %r2,%r11 # pass pointer to pt_regs |
736 | brasl %r14,s390_do_machine_check | 736 | brasl %r14,s390_do_machine_check |
737 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 737 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
738 | jno mcck_return | 738 | jno .Lmcck_return |
739 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack | 739 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack |
740 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 740 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
741 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 741 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
@@ -743,11 +743,11 @@ mcck_skip: | |||
743 | lgr %r15,%r1 | 743 | lgr %r15,%r1 |
744 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off | 744 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
745 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 745 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
746 | jno mcck_return | 746 | jno .Lmcck_return |
747 | TRACE_IRQS_OFF | 747 | TRACE_IRQS_OFF |
748 | brasl %r14,s390_handle_mcck | 748 | brasl %r14,s390_handle_mcck |
749 | TRACE_IRQS_ON | 749 | TRACE_IRQS_ON |
750 | mcck_return: | 750 | .Lmcck_return: |
751 | lg %r14,__LC_VDSO_PER_CPU | 751 | lg %r14,__LC_VDSO_PER_CPU |
752 | lmg %r0,%r10,__PT_R0(%r11) | 752 | lmg %r0,%r10,__PT_R0(%r11) |
753 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW | 753 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW |
@@ -758,14 +758,14 @@ mcck_return: | |||
758 | 0: lmg %r11,%r15,__PT_R11(%r11) | 758 | 0: lmg %r11,%r15,__PT_R11(%r11) |
759 | lpswe __LC_RETURN_MCCK_PSW | 759 | lpswe __LC_RETURN_MCCK_PSW |
760 | 760 | ||
761 | mcck_panic: | 761 | .Lmcck_panic: |
762 | lg %r14,__LC_PANIC_STACK | 762 | lg %r14,__LC_PANIC_STACK |
763 | slgr %r14,%r15 | 763 | slgr %r14,%r15 |
764 | srag %r14,%r14,PAGE_SHIFT | 764 | srag %r14,%r14,PAGE_SHIFT |
765 | jz 0f | 765 | jz 0f |
766 | lg %r15,__LC_PANIC_STACK | 766 | lg %r15,__LC_PANIC_STACK |
767 | 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 767 | 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
768 | j mcck_skip | 768 | j .Lmcck_skip |
769 | 769 | ||
770 | # | 770 | # |
771 | # PSW restart interrupt handler | 771 | # PSW restart interrupt handler |
@@ -815,69 +815,69 @@ stack_overflow: | |||
815 | #endif | 815 | #endif |
816 | 816 | ||
817 | .align 8 | 817 | .align 8 |
818 | cleanup_table: | 818 | .Lcleanup_table: |
819 | .quad system_call | 819 | .quad system_call |
820 | .quad sysc_do_svc | 820 | .quad .Lsysc_do_svc |
821 | .quad sysc_tif | 821 | .quad .Lsysc_tif |
822 | .quad sysc_restore | 822 | .quad .Lsysc_restore |
823 | .quad sysc_done | 823 | .quad .Lsysc_done |
824 | .quad io_tif | 824 | .quad .Lio_tif |
825 | .quad io_restore | 825 | .quad .Lio_restore |
826 | .quad io_done | 826 | .quad .Lio_done |
827 | .quad psw_idle | 827 | .quad psw_idle |
828 | .quad psw_idle_end | 828 | .quad .Lpsw_idle_end |
829 | 829 | ||
830 | cleanup_critical: | 830 | cleanup_critical: |
831 | clg %r9,BASED(cleanup_table) # system_call | 831 | clg %r9,BASED(.Lcleanup_table) # system_call |
832 | jl 0f | 832 | jl 0f |
833 | clg %r9,BASED(cleanup_table+8) # sysc_do_svc | 833 | clg %r9,BASED(.Lcleanup_table+8) # .Lsysc_do_svc |
834 | jl cleanup_system_call | 834 | jl .Lcleanup_system_call |
835 | clg %r9,BASED(cleanup_table+16) # sysc_tif | 835 | clg %r9,BASED(.Lcleanup_table+16) # .Lsysc_tif |
836 | jl 0f | 836 | jl 0f |
837 | clg %r9,BASED(cleanup_table+24) # sysc_restore | 837 | clg %r9,BASED(.Lcleanup_table+24) # .Lsysc_restore |
838 | jl cleanup_sysc_tif | 838 | jl .Lcleanup_sysc_tif |
839 | clg %r9,BASED(cleanup_table+32) # sysc_done | 839 | clg %r9,BASED(.Lcleanup_table+32) # .Lsysc_done |
840 | jl cleanup_sysc_restore | 840 | jl .Lcleanup_sysc_restore |
841 | clg %r9,BASED(cleanup_table+40) # io_tif | 841 | clg %r9,BASED(.Lcleanup_table+40) # .Lio_tif |
842 | jl 0f | 842 | jl 0f |
843 | clg %r9,BASED(cleanup_table+48) # io_restore | 843 | clg %r9,BASED(.Lcleanup_table+48) # .Lio_restore |
844 | jl cleanup_io_tif | 844 | jl .Lcleanup_io_tif |
845 | clg %r9,BASED(cleanup_table+56) # io_done | 845 | clg %r9,BASED(.Lcleanup_table+56) # .Lio_done |
846 | jl cleanup_io_restore | 846 | jl .Lcleanup_io_restore |
847 | clg %r9,BASED(cleanup_table+64) # psw_idle | 847 | clg %r9,BASED(.Lcleanup_table+64) # psw_idle |
848 | jl 0f | 848 | jl 0f |
849 | clg %r9,BASED(cleanup_table+72) # psw_idle_end | 849 | clg %r9,BASED(.Lcleanup_table+72) # .Lpsw_idle_end |
850 | jl cleanup_idle | 850 | jl .Lcleanup_idle |
851 | 0: br %r14 | 851 | 0: br %r14 |
852 | 852 | ||
853 | 853 | ||
854 | cleanup_system_call: | 854 | .Lcleanup_system_call: |
855 | # check if stpt has been executed | 855 | # check if stpt has been executed |
856 | clg %r9,BASED(cleanup_system_call_insn) | 856 | clg %r9,BASED(.Lcleanup_system_call_insn) |
857 | jh 0f | 857 | jh 0f |
858 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 858 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
859 | cghi %r11,__LC_SAVE_AREA_ASYNC | 859 | cghi %r11,__LC_SAVE_AREA_ASYNC |
860 | je 0f | 860 | je 0f |
861 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | 861 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
862 | 0: # check if stmg has been executed | 862 | 0: # check if stmg has been executed |
863 | clg %r9,BASED(cleanup_system_call_insn+8) | 863 | clg %r9,BASED(.Lcleanup_system_call_insn+8) |
864 | jh 0f | 864 | jh 0f |
865 | mvc __LC_SAVE_AREA_SYNC(64),0(%r11) | 865 | mvc __LC_SAVE_AREA_SYNC(64),0(%r11) |
866 | 0: # check if base register setup + TIF bit load has been done | 866 | 0: # check if base register setup + TIF bit load has been done |
867 | clg %r9,BASED(cleanup_system_call_insn+16) | 867 | clg %r9,BASED(.Lcleanup_system_call_insn+16) |
868 | jhe 0f | 868 | jhe 0f |
869 | # set up saved registers r10 and r12 | 869 | # set up saved registers r10 and r12 |
870 | stg %r10,16(%r11) # r10 last break | 870 | stg %r10,16(%r11) # r10 last break |
871 | stg %r12,32(%r11) # r12 thread-info pointer | 871 | stg %r12,32(%r11) # r12 thread-info pointer |
872 | 0: # check if the user time update has been done | 872 | 0: # check if the user time update has been done |
873 | clg %r9,BASED(cleanup_system_call_insn+24) | 873 | clg %r9,BASED(.Lcleanup_system_call_insn+24) |
874 | jh 0f | 874 | jh 0f |
875 | lg %r15,__LC_EXIT_TIMER | 875 | lg %r15,__LC_EXIT_TIMER |
876 | slg %r15,__LC_SYNC_ENTER_TIMER | 876 | slg %r15,__LC_SYNC_ENTER_TIMER |
877 | alg %r15,__LC_USER_TIMER | 877 | alg %r15,__LC_USER_TIMER |
878 | stg %r15,__LC_USER_TIMER | 878 | stg %r15,__LC_USER_TIMER |
879 | 0: # check if the system time update has been done | 879 | 0: # check if the system time update has been done |
880 | clg %r9,BASED(cleanup_system_call_insn+32) | 880 | clg %r9,BASED(.Lcleanup_system_call_insn+32) |
881 | jh 0f | 881 | jh 0f |
882 | lg %r15,__LC_LAST_UPDATE_TIMER | 882 | lg %r15,__LC_LAST_UPDATE_TIMER |
883 | slg %r15,__LC_EXIT_TIMER | 883 | slg %r15,__LC_EXIT_TIMER |
@@ -904,21 +904,21 @@ cleanup_system_call: | |||
904 | # setup saved register r15 | 904 | # setup saved register r15 |
905 | stg %r15,56(%r11) # r15 stack pointer | 905 | stg %r15,56(%r11) # r15 stack pointer |
906 | # set new psw address and exit | 906 | # set new psw address and exit |
907 | larl %r9,sysc_do_svc | 907 | larl %r9,.Lsysc_do_svc |
908 | br %r14 | 908 | br %r14 |
909 | cleanup_system_call_insn: | 909 | .Lcleanup_system_call_insn: |
910 | .quad system_call | 910 | .quad system_call |
911 | .quad sysc_stmg | 911 | .quad .Lsysc_stmg |
912 | .quad sysc_per | 912 | .quad .Lsysc_per |
913 | .quad sysc_vtime+18 | 913 | .quad .Lsysc_vtime+18 |
914 | .quad sysc_vtime+42 | 914 | .quad .Lsysc_vtime+42 |
915 | 915 | ||
916 | cleanup_sysc_tif: | 916 | .Lcleanup_sysc_tif: |
917 | larl %r9,sysc_tif | 917 | larl %r9,.Lsysc_tif |
918 | br %r14 | 918 | br %r14 |
919 | 919 | ||
920 | cleanup_sysc_restore: | 920 | .Lcleanup_sysc_restore: |
921 | clg %r9,BASED(cleanup_sysc_restore_insn) | 921 | clg %r9,BASED(.Lcleanup_sysc_restore_insn) |
922 | je 0f | 922 | je 0f |
923 | lg %r9,24(%r11) # get saved pointer to pt_regs | 923 | lg %r9,24(%r11) # get saved pointer to pt_regs |
924 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) | 924 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
@@ -926,15 +926,15 @@ cleanup_sysc_restore: | |||
926 | lmg %r0,%r7,__PT_R0(%r9) | 926 | lmg %r0,%r7,__PT_R0(%r9) |
927 | 0: lmg %r8,%r9,__LC_RETURN_PSW | 927 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
928 | br %r14 | 928 | br %r14 |
929 | cleanup_sysc_restore_insn: | 929 | .Lcleanup_sysc_restore_insn: |
930 | .quad sysc_done - 4 | 930 | .quad .Lsysc_done - 4 |
931 | 931 | ||
932 | cleanup_io_tif: | 932 | .Lcleanup_io_tif: |
933 | larl %r9,io_tif | 933 | larl %r9,.Lio_tif |
934 | br %r14 | 934 | br %r14 |
935 | 935 | ||
936 | cleanup_io_restore: | 936 | .Lcleanup_io_restore: |
937 | clg %r9,BASED(cleanup_io_restore_insn) | 937 | clg %r9,BASED(.Lcleanup_io_restore_insn) |
938 | je 0f | 938 | je 0f |
939 | lg %r9,24(%r11) # get saved r11 pointer to pt_regs | 939 | lg %r9,24(%r11) # get saved r11 pointer to pt_regs |
940 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) | 940 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
@@ -942,10 +942,10 @@ cleanup_io_restore: | |||
942 | lmg %r0,%r7,__PT_R0(%r9) | 942 | lmg %r0,%r7,__PT_R0(%r9) |
943 | 0: lmg %r8,%r9,__LC_RETURN_PSW | 943 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
944 | br %r14 | 944 | br %r14 |
945 | cleanup_io_restore_insn: | 945 | .Lcleanup_io_restore_insn: |
946 | .quad io_done - 4 | 946 | .quad .Lio_done - 4 |
947 | 947 | ||
948 | cleanup_idle: | 948 | .Lcleanup_idle: |
949 | # copy interrupt clock & cpu timer | 949 | # copy interrupt clock & cpu timer |
950 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK | 950 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK |
951 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER | 951 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER |
@@ -954,7 +954,7 @@ cleanup_idle: | |||
954 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK | 954 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK |
955 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER | 955 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER |
956 | 0: # check if stck & stpt have been executed | 956 | 0: # check if stck & stpt have been executed |
957 | clg %r9,BASED(cleanup_idle_insn) | 957 | clg %r9,BASED(.Lcleanup_idle_insn) |
958 | jhe 1f | 958 | jhe 1f |
959 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) | 959 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) |
960 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r2) | 960 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r2) |
@@ -973,17 +973,17 @@ cleanup_idle: | |||
973 | nihh %r8,0xfcfd # clear irq & wait state bits | 973 | nihh %r8,0xfcfd # clear irq & wait state bits |
974 | lg %r9,48(%r11) # return from psw_idle | 974 | lg %r9,48(%r11) # return from psw_idle |
975 | br %r14 | 975 | br %r14 |
976 | cleanup_idle_insn: | 976 | .Lcleanup_idle_insn: |
977 | .quad psw_idle_lpsw | 977 | .quad .Lpsw_idle_lpsw |
978 | 978 | ||
979 | /* | 979 | /* |
980 | * Integer constants | 980 | * Integer constants |
981 | */ | 981 | */ |
982 | .align 8 | 982 | .align 8 |
983 | .Lcritical_start: | 983 | .Lcritical_start: |
984 | .quad __critical_start | 984 | .quad .L__critical_start |
985 | .Lcritical_length: | 985 | .Lcritical_length: |
986 | .quad __critical_end - __critical_start | 986 | .quad .L__critical_end - .L__critical_start |
987 | 987 | ||
988 | 988 | ||
989 | #if IS_ENABLED(CONFIG_KVM) | 989 | #if IS_ENABLED(CONFIG_KVM) |
@@ -1000,25 +1000,25 @@ ENTRY(sie64a) | |||
1000 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | 1000 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 |
1001 | lg %r14,__LC_GMAP # get gmap pointer | 1001 | lg %r14,__LC_GMAP # get gmap pointer |
1002 | ltgr %r14,%r14 | 1002 | ltgr %r14,%r14 |
1003 | jz sie_gmap | 1003 | jz .Lsie_gmap |
1004 | lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce | 1004 | lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce |
1005 | sie_gmap: | 1005 | .Lsie_gmap: |
1006 | lg %r14,__SF_EMPTY(%r15) # get control block pointer | 1006 | lg %r14,__SF_EMPTY(%r15) # get control block pointer |
1007 | oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now | 1007 | oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now |
1008 | tm __SIE_PROG20+3(%r14),1 # last exit... | 1008 | tm __SIE_PROG20+3(%r14),1 # last exit... |
1009 | jnz sie_done | 1009 | jnz .Lsie_done |
1010 | LPP __SF_EMPTY(%r15) # set guest id | 1010 | LPP __SF_EMPTY(%r15) # set guest id |
1011 | sie 0(%r14) | 1011 | sie 0(%r14) |
1012 | sie_done: | 1012 | .Lsie_done: |
1013 | LPP __SF_EMPTY+16(%r15) # set host id | 1013 | LPP __SF_EMPTY+16(%r15) # set host id |
1014 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE | 1014 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE |
1015 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 1015 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
1016 | # some program checks are suppressing. C code (e.g. do_protection_exception) | 1016 | # some program checks are suppressing. C code (e.g. do_protection_exception) |
1017 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other | 1017 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other |
1018 | # instructions between sie64a and sie_done should not cause program | 1018 | # instructions between sie64a and .Lsie_done should not cause program |
1019 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. | 1019 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. |
1020 | # See also HANDLE_SIE_INTERCEPT | 1020 | # See also HANDLE_SIE_INTERCEPT |
1021 | rewind_pad: | 1021 | .Lrewind_pad: |
1022 | nop 0 | 1022 | nop 0 |
1023 | .globl sie_exit | 1023 | .globl sie_exit |
1024 | sie_exit: | 1024 | sie_exit: |
@@ -1027,19 +1027,19 @@ sie_exit: | |||
1027 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | 1027 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers |
1028 | lg %r2,__SF_EMPTY+24(%r15) # return exit reason code | 1028 | lg %r2,__SF_EMPTY+24(%r15) # return exit reason code |
1029 | br %r14 | 1029 | br %r14 |
1030 | sie_fault: | 1030 | .Lsie_fault: |
1031 | lghi %r14,-EFAULT | 1031 | lghi %r14,-EFAULT |
1032 | stg %r14,__SF_EMPTY+24(%r15) # set exit reason code | 1032 | stg %r14,__SF_EMPTY+24(%r15) # set exit reason code |
1033 | j sie_exit | 1033 | j sie_exit |
1034 | 1034 | ||
1035 | .align 8 | 1035 | .align 8 |
1036 | .Lsie_critical: | 1036 | .Lsie_critical: |
1037 | .quad sie_gmap | 1037 | .quad .Lsie_gmap |
1038 | .Lsie_critical_length: | 1038 | .Lsie_critical_length: |
1039 | .quad sie_done - sie_gmap | 1039 | .quad .Lsie_done - .Lsie_gmap |
1040 | 1040 | ||
1041 | EX_TABLE(rewind_pad,sie_fault) | 1041 | EX_TABLE(.Lrewind_pad,.Lsie_fault) |
1042 | EX_TABLE(sie_exit,sie_fault) | 1042 | EX_TABLE(sie_exit,.Lsie_fault) |
1043 | #endif | 1043 | #endif |
1044 | 1044 | ||
1045 | .section .rodata, "a" | 1045 | .section .rodata, "a" |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index ca1cabb3a96c..b86bb8823f15 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/moduleloader.h> | ||
10 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
11 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
12 | #include <linux/ftrace.h> | 13 | #include <linux/ftrace.h> |
@@ -15,60 +16,39 @@ | |||
15 | #include <linux/kprobes.h> | 16 | #include <linux/kprobes.h> |
16 | #include <trace/syscall.h> | 17 | #include <trace/syscall.h> |
17 | #include <asm/asm-offsets.h> | 18 | #include <asm/asm-offsets.h> |
19 | #include <asm/cacheflush.h> | ||
18 | #include "entry.h" | 20 | #include "entry.h" |
19 | 21 | ||
20 | void mcount_replace_code(void); | ||
21 | void ftrace_disable_code(void); | ||
22 | void ftrace_enable_insn(void); | ||
23 | |||
24 | /* | 22 | /* |
25 | * The mcount code looks like this: | 23 | * The mcount code looks like this: |
26 | * stg %r14,8(%r15) # offset 0 | 24 | * stg %r14,8(%r15) # offset 0 |
27 | * larl %r1,<&counter> # offset 6 | 25 | * larl %r1,<&counter> # offset 6 |
28 | * brasl %r14,_mcount # offset 12 | 26 | * brasl %r14,_mcount # offset 12 |
29 | * lg %r14,8(%r15) # offset 18 | 27 | * lg %r14,8(%r15) # offset 18 |
30 | * Total length is 24 bytes. The complete mcount block initially gets replaced | 28 | * Total length is 24 bytes. Only the first instruction will be patched |
31 | * by ftrace_make_nop. Subsequent calls to ftrace_make_call / ftrace_make_nop | 29 | * by ftrace_make_call / ftrace_make_nop. |
32 | * only patch the jg/lg instruction within the block. | ||
33 | * Note: we do not patch the first instruction to an unconditional branch, | ||
34 | * since that would break kprobes/jprobes. It is easier to leave the larl | ||
35 | * instruction in and only modify the second instruction. | ||
36 | * The enabled ftrace code block looks like this: | 30 | * The enabled ftrace code block looks like this: |
37 | * larl %r0,.+24 # offset 0 | 31 | * > brasl %r0,ftrace_caller # offset 0 |
38 | * > lg %r1,__LC_FTRACE_FUNC # offset 6 | 32 | * larl %r1,<&counter> # offset 6 |
39 | * br %r1 # offset 12 | 33 | * brasl %r14,_mcount # offset 12 |
40 | * brcl 0,0 # offset 14 | 34 | * lg %r14,8(%r15) # offset 18 |
41 | * brc 0,0 # offset 20 | ||
42 | * The ftrace function gets called with a non-standard C function call ABI | 35 | * The ftrace function gets called with a non-standard C function call ABI |
43 | * where r0 contains the return address. It is also expected that the called | 36 | * where r0 contains the return address. It is also expected that the called |
44 | * function only clobbers r0 and r1, but restores r2-r15. | 37 | * function only clobbers r0 and r1, but restores r2-r15. |
38 | * For module code we can't directly jump to ftrace caller, but need a | ||
39 | * trampoline (ftrace_plt), which clobbers also r1. | ||
45 | * The return point of the ftrace function has offset 24, so execution | 40 | * The return point of the ftrace function has offset 24, so execution |
46 | * continues behind the mcount block. | 41 | * continues behind the mcount block. |
47 | * larl %r0,.+24 # offset 0 | 42 | * The disabled ftrace code block looks like this: |
48 | * > jg .+18 # offset 6 | 43 | * > jg .+24 # offset 0 |
49 | * br %r1 # offset 12 | 44 | * larl %r1,<&counter> # offset 6 |
50 | * brcl 0,0 # offset 14 | 45 | * brasl %r14,_mcount # offset 12 |
51 | * brc 0,0 # offset 20 | 46 | * lg %r14,8(%r15) # offset 18 |
52 | * The jg instruction branches to offset 24 to skip as many instructions | 47 | * The jg instruction branches to offset 24 to skip as many instructions |
53 | * as possible. | 48 | * as possible. |
54 | */ | 49 | */ |
55 | asm( | 50 | |
56 | " .align 4\n" | 51 | unsigned long ftrace_plt; |
57 | "mcount_replace_code:\n" | ||
58 | " larl %r0,0f\n" | ||
59 | "ftrace_disable_code:\n" | ||
60 | " jg 0f\n" | ||
61 | " br %r1\n" | ||
62 | " brcl 0,0\n" | ||
63 | " brc 0,0\n" | ||
64 | "0:\n" | ||
65 | " .align 4\n" | ||
66 | "ftrace_enable_insn:\n" | ||
67 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n"); | ||
68 | |||
69 | #define MCOUNT_BLOCK_SIZE 24 | ||
70 | #define MCOUNT_INSN_OFFSET 6 | ||
71 | #define FTRACE_INSN_SIZE 6 | ||
72 | 52 | ||
73 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | 53 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, |
74 | unsigned long addr) | 54 | unsigned long addr) |
@@ -79,24 +59,62 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | |||
79 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | 59 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, |
80 | unsigned long addr) | 60 | unsigned long addr) |
81 | { | 61 | { |
82 | /* Initial replacement of the whole mcount block */ | 62 | struct ftrace_insn insn; |
83 | if (addr == MCOUNT_ADDR) { | 63 | unsigned short op; |
84 | if (probe_kernel_write((void *) rec->ip - MCOUNT_INSN_OFFSET, | 64 | void *from, *to; |
85 | mcount_replace_code, | 65 | size_t size; |
86 | MCOUNT_BLOCK_SIZE)) | 66 | |
87 | return -EPERM; | 67 | ftrace_generate_nop_insn(&insn); |
88 | return 0; | 68 | size = sizeof(insn); |
69 | from = &insn; | ||
70 | to = (void *) rec->ip; | ||
71 | if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) | ||
72 | return -EFAULT; | ||
73 | /* | ||
74 | * If we find a breakpoint instruction, a kprobe has been placed | ||
75 | * at the beginning of the function. We write the constant | ||
76 | * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original | ||
77 | * instruction so that the kprobes handler can execute a nop, if it | ||
78 | * reaches this breakpoint. | ||
79 | */ | ||
80 | if (op == BREAKPOINT_INSTRUCTION) { | ||
81 | size -= 2; | ||
82 | from += 2; | ||
83 | to += 2; | ||
84 | insn.disp = KPROBE_ON_FTRACE_NOP; | ||
89 | } | 85 | } |
90 | if (probe_kernel_write((void *) rec->ip, ftrace_disable_code, | 86 | if (probe_kernel_write(to, from, size)) |
91 | MCOUNT_INSN_SIZE)) | ||
92 | return -EPERM; | 87 | return -EPERM; |
93 | return 0; | 88 | return 0; |
94 | } | 89 | } |
95 | 90 | ||
96 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | 91 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) |
97 | { | 92 | { |
98 | if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn, | 93 | struct ftrace_insn insn; |
99 | FTRACE_INSN_SIZE)) | 94 | unsigned short op; |
95 | void *from, *to; | ||
96 | size_t size; | ||
97 | |||
98 | ftrace_generate_call_insn(&insn, rec->ip); | ||
99 | size = sizeof(insn); | ||
100 | from = &insn; | ||
101 | to = (void *) rec->ip; | ||
102 | if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) | ||
103 | return -EFAULT; | ||
104 | /* | ||
105 | * If we find a breakpoint instruction, a kprobe has been placed | ||
106 | * at the beginning of the function. We write the constant | ||
107 | * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original | ||
108 | * instruction so that the kprobes handler can execute a brasl if it | ||
109 | * reaches this breakpoint. | ||
110 | */ | ||
111 | if (op == BREAKPOINT_INSTRUCTION) { | ||
112 | size -= 2; | ||
113 | from += 2; | ||
114 | to += 2; | ||
115 | insn.disp = KPROBE_ON_FTRACE_CALL; | ||
116 | } | ||
117 | if (probe_kernel_write(to, from, size)) | ||
100 | return -EPERM; | 118 | return -EPERM; |
101 | return 0; | 119 | return 0; |
102 | } | 120 | } |
@@ -111,13 +129,30 @@ int __init ftrace_dyn_arch_init(void) | |||
111 | return 0; | 129 | return 0; |
112 | } | 130 | } |
113 | 131 | ||
132 | static int __init ftrace_plt_init(void) | ||
133 | { | ||
134 | unsigned int *ip; | ||
135 | |||
136 | ftrace_plt = (unsigned long) module_alloc(PAGE_SIZE); | ||
137 | if (!ftrace_plt) | ||
138 | panic("cannot allocate ftrace plt\n"); | ||
139 | ip = (unsigned int *) ftrace_plt; | ||
140 | ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ | ||
141 | ip[1] = 0x100a0004; | ||
142 | ip[2] = 0x07f10000; | ||
143 | ip[3] = FTRACE_ADDR >> 32; | ||
144 | ip[4] = FTRACE_ADDR & 0xffffffff; | ||
145 | set_memory_ro(ftrace_plt, 1); | ||
146 | return 0; | ||
147 | } | ||
148 | device_initcall(ftrace_plt_init); | ||
149 | |||
114 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 150 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
115 | /* | 151 | /* |
116 | * Hook the return address and push it in the stack of return addresses | 152 | * Hook the return address and push it in the stack of return addresses |
117 | * in current thread info. | 153 | * in current thread info. |
118 | */ | 154 | */ |
119 | unsigned long __kprobes prepare_ftrace_return(unsigned long parent, | 155 | unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip) |
120 | unsigned long ip) | ||
121 | { | 156 | { |
122 | struct ftrace_graph_ent trace; | 157 | struct ftrace_graph_ent trace; |
123 | 158 | ||
@@ -137,6 +172,7 @@ unsigned long __kprobes prepare_ftrace_return(unsigned long parent, | |||
137 | out: | 172 | out: |
138 | return parent; | 173 | return parent; |
139 | } | 174 | } |
175 | NOKPROBE_SYMBOL(prepare_ftrace_return); | ||
140 | 176 | ||
141 | /* | 177 | /* |
142 | * Patch the kernel code at ftrace_graph_caller location. The instruction | 178 | * Patch the kernel code at ftrace_graph_caller location. The instruction |
diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c index 7559f1beab29..7a55c29b0b33 100644 --- a/arch/s390/kernel/idle.c +++ b/arch/s390/kernel/idle.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | static DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | 20 | static DEFINE_PER_CPU(struct s390_idle_data, s390_idle); |
21 | 21 | ||
22 | void __kprobes enabled_wait(void) | 22 | void enabled_wait(void) |
23 | { | 23 | { |
24 | struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); | 24 | struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); |
25 | unsigned long long idle_time; | 25 | unsigned long long idle_time; |
@@ -35,31 +35,32 @@ void __kprobes enabled_wait(void) | |||
35 | /* Call the assembler magic in entry.S */ | 35 | /* Call the assembler magic in entry.S */ |
36 | psw_idle(idle, psw_mask); | 36 | psw_idle(idle, psw_mask); |
37 | 37 | ||
38 | trace_hardirqs_off(); | ||
39 | |||
38 | /* Account time spent with enabled wait psw loaded as idle time. */ | 40 | /* Account time spent with enabled wait psw loaded as idle time. */ |
39 | idle->sequence++; | 41 | write_seqcount_begin(&idle->seqcount); |
40 | smp_wmb(); | ||
41 | idle_time = idle->clock_idle_exit - idle->clock_idle_enter; | 42 | idle_time = idle->clock_idle_exit - idle->clock_idle_enter; |
42 | idle->clock_idle_enter = idle->clock_idle_exit = 0ULL; | 43 | idle->clock_idle_enter = idle->clock_idle_exit = 0ULL; |
43 | idle->idle_time += idle_time; | 44 | idle->idle_time += idle_time; |
44 | idle->idle_count++; | 45 | idle->idle_count++; |
45 | account_idle_time(idle_time); | 46 | account_idle_time(idle_time); |
46 | smp_wmb(); | 47 | write_seqcount_end(&idle->seqcount); |
47 | idle->sequence++; | ||
48 | } | 48 | } |
49 | NOKPROBE_SYMBOL(enabled_wait); | ||
49 | 50 | ||
50 | static ssize_t show_idle_count(struct device *dev, | 51 | static ssize_t show_idle_count(struct device *dev, |
51 | struct device_attribute *attr, char *buf) | 52 | struct device_attribute *attr, char *buf) |
52 | { | 53 | { |
53 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); | 54 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); |
54 | unsigned long long idle_count; | 55 | unsigned long long idle_count; |
55 | unsigned int sequence; | 56 | unsigned int seq; |
56 | 57 | ||
57 | do { | 58 | do { |
58 | sequence = ACCESS_ONCE(idle->sequence); | 59 | seq = read_seqcount_begin(&idle->seqcount); |
59 | idle_count = ACCESS_ONCE(idle->idle_count); | 60 | idle_count = ACCESS_ONCE(idle->idle_count); |
60 | if (ACCESS_ONCE(idle->clock_idle_enter)) | 61 | if (ACCESS_ONCE(idle->clock_idle_enter)) |
61 | idle_count++; | 62 | idle_count++; |
62 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 63 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
63 | return sprintf(buf, "%llu\n", idle_count); | 64 | return sprintf(buf, "%llu\n", idle_count); |
64 | } | 65 | } |
65 | DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); | 66 | DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); |
@@ -69,15 +70,15 @@ static ssize_t show_idle_time(struct device *dev, | |||
69 | { | 70 | { |
70 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); | 71 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); |
71 | unsigned long long now, idle_time, idle_enter, idle_exit; | 72 | unsigned long long now, idle_time, idle_enter, idle_exit; |
72 | unsigned int sequence; | 73 | unsigned int seq; |
73 | 74 | ||
74 | do { | 75 | do { |
75 | now = get_tod_clock(); | 76 | now = get_tod_clock(); |
76 | sequence = ACCESS_ONCE(idle->sequence); | 77 | seq = read_seqcount_begin(&idle->seqcount); |
77 | idle_time = ACCESS_ONCE(idle->idle_time); | 78 | idle_time = ACCESS_ONCE(idle->idle_time); |
78 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); | 79 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); |
79 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); | 80 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); |
80 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 81 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
81 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; | 82 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; |
82 | return sprintf(buf, "%llu\n", idle_time >> 12); | 83 | return sprintf(buf, "%llu\n", idle_time >> 12); |
83 | } | 84 | } |
@@ -87,14 +88,14 @@ cputime64_t arch_cpu_idle_time(int cpu) | |||
87 | { | 88 | { |
88 | struct s390_idle_data *idle = &per_cpu(s390_idle, cpu); | 89 | struct s390_idle_data *idle = &per_cpu(s390_idle, cpu); |
89 | unsigned long long now, idle_enter, idle_exit; | 90 | unsigned long long now, idle_enter, idle_exit; |
90 | unsigned int sequence; | 91 | unsigned int seq; |
91 | 92 | ||
92 | do { | 93 | do { |
93 | now = get_tod_clock(); | 94 | now = get_tod_clock(); |
94 | sequence = ACCESS_ONCE(idle->sequence); | 95 | seq = read_seqcount_begin(&idle->seqcount); |
95 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); | 96 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); |
96 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); | 97 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); |
97 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 98 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
98 | return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0; | 99 | return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0; |
99 | } | 100 | } |
100 | 101 | ||
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1b8a38ab7861..f238720690f3 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -127,13 +127,10 @@ int show_interrupts(struct seq_file *p, void *v) | |||
127 | for_each_online_cpu(cpu) | 127 | for_each_online_cpu(cpu) |
128 | seq_printf(p, "CPU%d ", cpu); | 128 | seq_printf(p, "CPU%d ", cpu); |
129 | seq_putc(p, '\n'); | 129 | seq_putc(p, '\n'); |
130 | goto out; | ||
131 | } | 130 | } |
132 | if (index < NR_IRQS) { | 131 | if (index < NR_IRQS) { |
133 | if (index >= NR_IRQS_BASE) | 132 | if (index >= NR_IRQS_BASE) |
134 | goto out; | 133 | goto out; |
135 | /* Adjust index to process irqclass_main_desc array entries */ | ||
136 | index--; | ||
137 | seq_printf(p, "%s: ", irqclass_main_desc[index].name); | 134 | seq_printf(p, "%s: ", irqclass_main_desc[index].name); |
138 | irq = irqclass_main_desc[index].irq; | 135 | irq = irqclass_main_desc[index].irq; |
139 | for_each_online_cpu(cpu) | 136 | for_each_online_cpu(cpu) |
@@ -158,7 +155,7 @@ out: | |||
158 | 155 | ||
159 | unsigned int arch_dynirq_lower_bound(unsigned int from) | 156 | unsigned int arch_dynirq_lower_bound(unsigned int from) |
160 | { | 157 | { |
161 | return from < THIN_INTERRUPT ? THIN_INTERRUPT : from; | 158 | return from < NR_IRQS_BASE ? NR_IRQS_BASE : from; |
162 | } | 159 | } |
163 | 160 | ||
164 | /* | 161 | /* |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 014d4729b134..1e4c710dfb92 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/hardirq.h> | 31 | #include <linux/hardirq.h> |
32 | #include <linux/ftrace.h> | ||
32 | #include <asm/cacheflush.h> | 33 | #include <asm/cacheflush.h> |
33 | #include <asm/sections.h> | 34 | #include <asm/sections.h> |
34 | #include <asm/dis.h> | 35 | #include <asm/dis.h> |
@@ -58,12 +59,23 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { | |||
58 | .insn_size = MAX_INSN_SIZE, | 59 | .insn_size = MAX_INSN_SIZE, |
59 | }; | 60 | }; |
60 | 61 | ||
61 | static void __kprobes copy_instruction(struct kprobe *p) | 62 | static void copy_instruction(struct kprobe *p) |
62 | { | 63 | { |
64 | unsigned long ip = (unsigned long) p->addr; | ||
63 | s64 disp, new_disp; | 65 | s64 disp, new_disp; |
64 | u64 addr, new_addr; | 66 | u64 addr, new_addr; |
65 | 67 | ||
66 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); | 68 | if (ftrace_location(ip) == ip) { |
69 | /* | ||
70 | * If kprobes patches the instruction that is morphed by | ||
71 | * ftrace make sure that kprobes always sees the branch | ||
72 | * "jg .+24" that skips the mcount block | ||
73 | */ | ||
74 | ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn); | ||
75 | p->ainsn.is_ftrace_insn = 1; | ||
76 | } else | ||
77 | memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8)); | ||
78 | p->opcode = p->ainsn.insn[0]; | ||
67 | if (!probe_is_insn_relative_long(p->ainsn.insn)) | 79 | if (!probe_is_insn_relative_long(p->ainsn.insn)) |
68 | return; | 80 | return; |
69 | /* | 81 | /* |
@@ -79,25 +91,14 @@ static void __kprobes copy_instruction(struct kprobe *p) | |||
79 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; | 91 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; |
80 | *(s32 *)&p->ainsn.insn[1] = new_disp; | 92 | *(s32 *)&p->ainsn.insn[1] = new_disp; |
81 | } | 93 | } |
94 | NOKPROBE_SYMBOL(copy_instruction); | ||
82 | 95 | ||
83 | static inline int is_kernel_addr(void *addr) | 96 | static inline int is_kernel_addr(void *addr) |
84 | { | 97 | { |
85 | return addr < (void *)_end; | 98 | return addr < (void *)_end; |
86 | } | 99 | } |
87 | 100 | ||
88 | static inline int is_module_addr(void *addr) | 101 | static int s390_get_insn_slot(struct kprobe *p) |
89 | { | ||
90 | #ifdef CONFIG_64BIT | ||
91 | BUILD_BUG_ON(MODULES_LEN > (1UL << 31)); | ||
92 | if (addr < (void *)MODULES_VADDR) | ||
93 | return 0; | ||
94 | if (addr > (void *)MODULES_END) | ||
95 | return 0; | ||
96 | #endif | ||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | static int __kprobes s390_get_insn_slot(struct kprobe *p) | ||
101 | { | 102 | { |
102 | /* | 103 | /* |
103 | * Get an insn slot that is within the same 2GB area like the original | 104 | * Get an insn slot that is within the same 2GB area like the original |
@@ -111,8 +112,9 @@ static int __kprobes s390_get_insn_slot(struct kprobe *p) | |||
111 | p->ainsn.insn = get_insn_slot(); | 112 | p->ainsn.insn = get_insn_slot(); |
112 | return p->ainsn.insn ? 0 : -ENOMEM; | 113 | return p->ainsn.insn ? 0 : -ENOMEM; |
113 | } | 114 | } |
115 | NOKPROBE_SYMBOL(s390_get_insn_slot); | ||
114 | 116 | ||
115 | static void __kprobes s390_free_insn_slot(struct kprobe *p) | 117 | static void s390_free_insn_slot(struct kprobe *p) |
116 | { | 118 | { |
117 | if (!p->ainsn.insn) | 119 | if (!p->ainsn.insn) |
118 | return; | 120 | return; |
@@ -122,8 +124,9 @@ static void __kprobes s390_free_insn_slot(struct kprobe *p) | |||
122 | free_insn_slot(p->ainsn.insn, 0); | 124 | free_insn_slot(p->ainsn.insn, 0); |
123 | p->ainsn.insn = NULL; | 125 | p->ainsn.insn = NULL; |
124 | } | 126 | } |
127 | NOKPROBE_SYMBOL(s390_free_insn_slot); | ||
125 | 128 | ||
126 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 129 | int arch_prepare_kprobe(struct kprobe *p) |
127 | { | 130 | { |
128 | if ((unsigned long) p->addr & 0x01) | 131 | if ((unsigned long) p->addr & 0x01) |
129 | return -EINVAL; | 132 | return -EINVAL; |
@@ -132,54 +135,79 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
132 | return -EINVAL; | 135 | return -EINVAL; |
133 | if (s390_get_insn_slot(p)) | 136 | if (s390_get_insn_slot(p)) |
134 | return -ENOMEM; | 137 | return -ENOMEM; |
135 | p->opcode = *p->addr; | ||
136 | copy_instruction(p); | 138 | copy_instruction(p); |
137 | return 0; | 139 | return 0; |
138 | } | 140 | } |
141 | NOKPROBE_SYMBOL(arch_prepare_kprobe); | ||
139 | 142 | ||
140 | struct ins_replace_args { | 143 | int arch_check_ftrace_location(struct kprobe *p) |
141 | kprobe_opcode_t *ptr; | 144 | { |
142 | kprobe_opcode_t opcode; | 145 | return 0; |
146 | } | ||
147 | |||
148 | struct swap_insn_args { | ||
149 | struct kprobe *p; | ||
150 | unsigned int arm_kprobe : 1; | ||
143 | }; | 151 | }; |
144 | 152 | ||
145 | static int __kprobes swap_instruction(void *aref) | 153 | static int swap_instruction(void *data) |
146 | { | 154 | { |
147 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 155 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
148 | unsigned long status = kcb->kprobe_status; | 156 | unsigned long status = kcb->kprobe_status; |
149 | struct ins_replace_args *args = aref; | 157 | struct swap_insn_args *args = data; |
150 | 158 | struct ftrace_insn new_insn, *insn; | |
159 | struct kprobe *p = args->p; | ||
160 | size_t len; | ||
161 | |||
162 | new_insn.opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode; | ||
163 | len = sizeof(new_insn.opc); | ||
164 | if (!p->ainsn.is_ftrace_insn) | ||
165 | goto skip_ftrace; | ||
166 | len = sizeof(new_insn); | ||
167 | insn = (struct ftrace_insn *) p->addr; | ||
168 | if (args->arm_kprobe) { | ||
169 | if (is_ftrace_nop(insn)) | ||
170 | new_insn.disp = KPROBE_ON_FTRACE_NOP; | ||
171 | else | ||
172 | new_insn.disp = KPROBE_ON_FTRACE_CALL; | ||
173 | } else { | ||
174 | ftrace_generate_call_insn(&new_insn, (unsigned long)p->addr); | ||
175 | if (insn->disp == KPROBE_ON_FTRACE_NOP) | ||
176 | ftrace_generate_nop_insn(&new_insn); | ||
177 | } | ||
178 | skip_ftrace: | ||
151 | kcb->kprobe_status = KPROBE_SWAP_INST; | 179 | kcb->kprobe_status = KPROBE_SWAP_INST; |
152 | probe_kernel_write(args->ptr, &args->opcode, sizeof(args->opcode)); | 180 | probe_kernel_write(p->addr, &new_insn, len); |
153 | kcb->kprobe_status = status; | 181 | kcb->kprobe_status = status; |
154 | return 0; | 182 | return 0; |
155 | } | 183 | } |
184 | NOKPROBE_SYMBOL(swap_instruction); | ||
156 | 185 | ||
157 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 186 | void arch_arm_kprobe(struct kprobe *p) |
158 | { | 187 | { |
159 | struct ins_replace_args args; | 188 | struct swap_insn_args args = {.p = p, .arm_kprobe = 1}; |
160 | 189 | ||
161 | args.ptr = p->addr; | ||
162 | args.opcode = BREAKPOINT_INSTRUCTION; | ||
163 | stop_machine(swap_instruction, &args, NULL); | 190 | stop_machine(swap_instruction, &args, NULL); |
164 | } | 191 | } |
192 | NOKPROBE_SYMBOL(arch_arm_kprobe); | ||
165 | 193 | ||
166 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 194 | void arch_disarm_kprobe(struct kprobe *p) |
167 | { | 195 | { |
168 | struct ins_replace_args args; | 196 | struct swap_insn_args args = {.p = p, .arm_kprobe = 0}; |
169 | 197 | ||
170 | args.ptr = p->addr; | ||
171 | args.opcode = p->opcode; | ||
172 | stop_machine(swap_instruction, &args, NULL); | 198 | stop_machine(swap_instruction, &args, NULL); |
173 | } | 199 | } |
200 | NOKPROBE_SYMBOL(arch_disarm_kprobe); | ||
174 | 201 | ||
175 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 202 | void arch_remove_kprobe(struct kprobe *p) |
176 | { | 203 | { |
177 | s390_free_insn_slot(p); | 204 | s390_free_insn_slot(p); |
178 | } | 205 | } |
206 | NOKPROBE_SYMBOL(arch_remove_kprobe); | ||
179 | 207 | ||
180 | static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, | 208 | static void enable_singlestep(struct kprobe_ctlblk *kcb, |
181 | struct pt_regs *regs, | 209 | struct pt_regs *regs, |
182 | unsigned long ip) | 210 | unsigned long ip) |
183 | { | 211 | { |
184 | struct per_regs per_kprobe; | 212 | struct per_regs per_kprobe; |
185 | 213 | ||
@@ -199,10 +227,11 @@ static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, | |||
199 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); | 227 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); |
200 | regs->psw.addr = ip | PSW_ADDR_AMODE; | 228 | regs->psw.addr = ip | PSW_ADDR_AMODE; |
201 | } | 229 | } |
230 | NOKPROBE_SYMBOL(enable_singlestep); | ||
202 | 231 | ||
203 | static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, | 232 | static void disable_singlestep(struct kprobe_ctlblk *kcb, |
204 | struct pt_regs *regs, | 233 | struct pt_regs *regs, |
205 | unsigned long ip) | 234 | unsigned long ip) |
206 | { | 235 | { |
207 | /* Restore control regs and psw mask, set new psw address */ | 236 | /* Restore control regs and psw mask, set new psw address */ |
208 | __ctl_load(kcb->kprobe_saved_ctl, 9, 11); | 237 | __ctl_load(kcb->kprobe_saved_ctl, 9, 11); |
@@ -210,41 +239,43 @@ static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, | |||
210 | regs->psw.mask |= kcb->kprobe_saved_imask; | 239 | regs->psw.mask |= kcb->kprobe_saved_imask; |
211 | regs->psw.addr = ip | PSW_ADDR_AMODE; | 240 | regs->psw.addr = ip | PSW_ADDR_AMODE; |
212 | } | 241 | } |
242 | NOKPROBE_SYMBOL(disable_singlestep); | ||
213 | 243 | ||
214 | /* | 244 | /* |
215 | * Activate a kprobe by storing its pointer to current_kprobe. The | 245 | * Activate a kprobe by storing its pointer to current_kprobe. The |
216 | * previous kprobe is stored in kcb->prev_kprobe. A stack of up to | 246 | * previous kprobe is stored in kcb->prev_kprobe. A stack of up to |
217 | * two kprobes can be active, see KPROBE_REENTER. | 247 | * two kprobes can be active, see KPROBE_REENTER. |
218 | */ | 248 | */ |
219 | static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) | 249 | static void push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) |
220 | { | 250 | { |
221 | kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); | 251 | kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); |
222 | kcb->prev_kprobe.status = kcb->kprobe_status; | 252 | kcb->prev_kprobe.status = kcb->kprobe_status; |
223 | __this_cpu_write(current_kprobe, p); | 253 | __this_cpu_write(current_kprobe, p); |
224 | } | 254 | } |
255 | NOKPROBE_SYMBOL(push_kprobe); | ||
225 | 256 | ||
226 | /* | 257 | /* |
227 | * Deactivate a kprobe by backing up to the previous state. If the | 258 | * Deactivate a kprobe by backing up to the previous state. If the |
228 | * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, | 259 | * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, |
229 | * for any other state prev_kprobe.kp will be NULL. | 260 | * for any other state prev_kprobe.kp will be NULL. |
230 | */ | 261 | */ |
231 | static void __kprobes pop_kprobe(struct kprobe_ctlblk *kcb) | 262 | static void pop_kprobe(struct kprobe_ctlblk *kcb) |
232 | { | 263 | { |
233 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); | 264 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); |
234 | kcb->kprobe_status = kcb->prev_kprobe.status; | 265 | kcb->kprobe_status = kcb->prev_kprobe.status; |
235 | } | 266 | } |
267 | NOKPROBE_SYMBOL(pop_kprobe); | ||
236 | 268 | ||
237 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 269 | void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) |
238 | struct pt_regs *regs) | ||
239 | { | 270 | { |
240 | ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; | 271 | ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; |
241 | 272 | ||
242 | /* Replace the return addr with trampoline addr */ | 273 | /* Replace the return addr with trampoline addr */ |
243 | regs->gprs[14] = (unsigned long) &kretprobe_trampoline; | 274 | regs->gprs[14] = (unsigned long) &kretprobe_trampoline; |
244 | } | 275 | } |
276 | NOKPROBE_SYMBOL(arch_prepare_kretprobe); | ||
245 | 277 | ||
246 | static void __kprobes kprobe_reenter_check(struct kprobe_ctlblk *kcb, | 278 | static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p) |
247 | struct kprobe *p) | ||
248 | { | 279 | { |
249 | switch (kcb->kprobe_status) { | 280 | switch (kcb->kprobe_status) { |
250 | case KPROBE_HIT_SSDONE: | 281 | case KPROBE_HIT_SSDONE: |
@@ -264,8 +295,9 @@ static void __kprobes kprobe_reenter_check(struct kprobe_ctlblk *kcb, | |||
264 | BUG(); | 295 | BUG(); |
265 | } | 296 | } |
266 | } | 297 | } |
298 | NOKPROBE_SYMBOL(kprobe_reenter_check); | ||
267 | 299 | ||
268 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 300 | static int kprobe_handler(struct pt_regs *regs) |
269 | { | 301 | { |
270 | struct kprobe_ctlblk *kcb; | 302 | struct kprobe_ctlblk *kcb; |
271 | struct kprobe *p; | 303 | struct kprobe *p; |
@@ -339,6 +371,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
339 | preempt_enable_no_resched(); | 371 | preempt_enable_no_resched(); |
340 | return 0; | 372 | return 0; |
341 | } | 373 | } |
374 | NOKPROBE_SYMBOL(kprobe_handler); | ||
342 | 375 | ||
343 | /* | 376 | /* |
344 | * Function return probe trampoline: | 377 | * Function return probe trampoline: |
@@ -355,8 +388,7 @@ static void __used kretprobe_trampoline_holder(void) | |||
355 | /* | 388 | /* |
356 | * Called when the probe at kretprobe trampoline is hit | 389 | * Called when the probe at kretprobe trampoline is hit |
357 | */ | 390 | */ |
358 | static int __kprobes trampoline_probe_handler(struct kprobe *p, | 391 | static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
359 | struct pt_regs *regs) | ||
360 | { | 392 | { |
361 | struct kretprobe_instance *ri; | 393 | struct kretprobe_instance *ri; |
362 | struct hlist_head *head, empty_rp; | 394 | struct hlist_head *head, empty_rp; |
@@ -444,6 +476,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
444 | */ | 476 | */ |
445 | return 1; | 477 | return 1; |
446 | } | 478 | } |
479 | NOKPROBE_SYMBOL(trampoline_probe_handler); | ||
447 | 480 | ||
448 | /* | 481 | /* |
449 | * Called after single-stepping. p->addr is the address of the | 482 | * Called after single-stepping. p->addr is the address of the |
@@ -453,12 +486,30 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
453 | * single-stepped a copy of the instruction. The address of this | 486 | * single-stepped a copy of the instruction. The address of this |
454 | * copy is p->ainsn.insn. | 487 | * copy is p->ainsn.insn. |
455 | */ | 488 | */ |
456 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | 489 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) |
457 | { | 490 | { |
458 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 491 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
459 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; | 492 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; |
460 | int fixup = probe_get_fixup_type(p->ainsn.insn); | 493 | int fixup = probe_get_fixup_type(p->ainsn.insn); |
461 | 494 | ||
495 | /* Check if the kprobes location is an enabled ftrace caller */ | ||
496 | if (p->ainsn.is_ftrace_insn) { | ||
497 | struct ftrace_insn *insn = (struct ftrace_insn *) p->addr; | ||
498 | struct ftrace_insn call_insn; | ||
499 | |||
500 | ftrace_generate_call_insn(&call_insn, (unsigned long) p->addr); | ||
501 | /* | ||
502 | * A kprobe on an enabled ftrace call site actually single | ||
503 | * stepped an unconditional branch (ftrace nop equivalent). | ||
504 | * Now we need to fixup things and pretend that a brasl r0,... | ||
505 | * was executed instead. | ||
506 | */ | ||
507 | if (insn->disp == KPROBE_ON_FTRACE_CALL) { | ||
508 | ip += call_insn.disp * 2 - MCOUNT_INSN_SIZE; | ||
509 | regs->gprs[0] = (unsigned long)p->addr + sizeof(*insn); | ||
510 | } | ||
511 | } | ||
512 | |||
462 | if (fixup & FIXUP_PSW_NORMAL) | 513 | if (fixup & FIXUP_PSW_NORMAL) |
463 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; | 514 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |
464 | 515 | ||
@@ -476,8 +527,9 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
476 | 527 | ||
477 | disable_singlestep(kcb, regs, ip); | 528 | disable_singlestep(kcb, regs, ip); |
478 | } | 529 | } |
530 | NOKPROBE_SYMBOL(resume_execution); | ||
479 | 531 | ||
480 | static int __kprobes post_kprobe_handler(struct pt_regs *regs) | 532 | static int post_kprobe_handler(struct pt_regs *regs) |
481 | { | 533 | { |
482 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 534 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
483 | struct kprobe *p = kprobe_running(); | 535 | struct kprobe *p = kprobe_running(); |
@@ -504,8 +556,9 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) | |||
504 | 556 | ||
505 | return 1; | 557 | return 1; |
506 | } | 558 | } |
559 | NOKPROBE_SYMBOL(post_kprobe_handler); | ||
507 | 560 | ||
508 | static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) | 561 | static int kprobe_trap_handler(struct pt_regs *regs, int trapnr) |
509 | { | 562 | { |
510 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 563 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
511 | struct kprobe *p = kprobe_running(); | 564 | struct kprobe *p = kprobe_running(); |
@@ -567,8 +620,9 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) | |||
567 | } | 620 | } |
568 | return 0; | 621 | return 0; |
569 | } | 622 | } |
623 | NOKPROBE_SYMBOL(kprobe_trap_handler); | ||
570 | 624 | ||
571 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 625 | int kprobe_fault_handler(struct pt_regs *regs, int trapnr) |
572 | { | 626 | { |
573 | int ret; | 627 | int ret; |
574 | 628 | ||
@@ -579,12 +633,13 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
579 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | 633 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); |
580 | return ret; | 634 | return ret; |
581 | } | 635 | } |
636 | NOKPROBE_SYMBOL(kprobe_fault_handler); | ||
582 | 637 | ||
583 | /* | 638 | /* |
584 | * Wrapper routine to for handling exceptions. | 639 | * Wrapper routine to for handling exceptions. |
585 | */ | 640 | */ |
586 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | 641 | int kprobe_exceptions_notify(struct notifier_block *self, |
587 | unsigned long val, void *data) | 642 | unsigned long val, void *data) |
588 | { | 643 | { |
589 | struct die_args *args = (struct die_args *) data; | 644 | struct die_args *args = (struct die_args *) data; |
590 | struct pt_regs *regs = args->regs; | 645 | struct pt_regs *regs = args->regs; |
@@ -616,8 +671,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
616 | 671 | ||
617 | return ret; | 672 | return ret; |
618 | } | 673 | } |
674 | NOKPROBE_SYMBOL(kprobe_exceptions_notify); | ||
619 | 675 | ||
620 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 676 | int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
621 | { | 677 | { |
622 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 678 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
623 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 679 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
@@ -635,13 +691,15 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
635 | memcpy(kcb->jprobes_stack, (void *) stack, MIN_STACK_SIZE(stack)); | 691 | memcpy(kcb->jprobes_stack, (void *) stack, MIN_STACK_SIZE(stack)); |
636 | return 1; | 692 | return 1; |
637 | } | 693 | } |
694 | NOKPROBE_SYMBOL(setjmp_pre_handler); | ||
638 | 695 | ||
639 | void __kprobes jprobe_return(void) | 696 | void jprobe_return(void) |
640 | { | 697 | { |
641 | asm volatile(".word 0x0002"); | 698 | asm volatile(".word 0x0002"); |
642 | } | 699 | } |
700 | NOKPROBE_SYMBOL(jprobe_return); | ||
643 | 701 | ||
644 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 702 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
645 | { | 703 | { |
646 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 704 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
647 | unsigned long stack; | 705 | unsigned long stack; |
@@ -655,6 +713,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
655 | preempt_enable_no_resched(); | 713 | preempt_enable_no_resched(); |
656 | return 1; | 714 | return 1; |
657 | } | 715 | } |
716 | NOKPROBE_SYMBOL(longjmp_break_handler); | ||
658 | 717 | ||
659 | static struct kprobe trampoline = { | 718 | static struct kprobe trampoline = { |
660 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | 719 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, |
@@ -666,7 +725,8 @@ int __init arch_init_kprobes(void) | |||
666 | return register_kprobe(&trampoline); | 725 | return register_kprobe(&trampoline); |
667 | } | 726 | } |
668 | 727 | ||
669 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | 728 | int arch_trampoline_kprobe(struct kprobe *p) |
670 | { | 729 | { |
671 | return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline; | 730 | return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline; |
672 | } | 731 | } |
732 | NOKPROBE_SYMBOL(arch_trampoline_kprobe); | ||
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 4300ea374826..b6dfc5bfcb89 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S | |||
@@ -27,6 +27,7 @@ ENTRY(ftrace_caller) | |||
27 | .globl ftrace_regs_caller | 27 | .globl ftrace_regs_caller |
28 | .set ftrace_regs_caller,ftrace_caller | 28 | .set ftrace_regs_caller,ftrace_caller |
29 | lgr %r1,%r15 | 29 | lgr %r1,%r15 |
30 | aghi %r0,MCOUNT_RETURN_FIXUP | ||
30 | aghi %r15,-STACK_FRAME_SIZE | 31 | aghi %r15,-STACK_FRAME_SIZE |
31 | stg %r1,__SF_BACKCHAIN(%r15) | 32 | stg %r1,__SF_BACKCHAIN(%r15) |
32 | stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) | 33 | stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) |
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index b878f12a9597..c3f8d157cb0d 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c | |||
@@ -1383,7 +1383,6 @@ static int cpumsf_pmu_add(struct perf_event *event, int flags) | |||
1383 | cpuhw->lsctl.ed = 1; | 1383 | cpuhw->lsctl.ed = 1; |
1384 | 1384 | ||
1385 | /* Set in_use flag and store event */ | 1385 | /* Set in_use flag and store event */ |
1386 | event->hw.idx = 0; /* only one sampling event per CPU supported */ | ||
1387 | cpuhw->event = event; | 1386 | cpuhw->event = event; |
1388 | cpuhw->flags |= PMU_F_IN_USE; | 1387 | cpuhw->flags |= PMU_F_IN_USE; |
1389 | 1388 | ||
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index ed84cc224899..aa7a83948c7b 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -61,7 +61,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
61 | return sf->gprs[8]; | 61 | return sf->gprs[8]; |
62 | } | 62 | } |
63 | 63 | ||
64 | extern void __kprobes kernel_thread_starter(void); | 64 | extern void kernel_thread_starter(void); |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Free current thread data structures etc.. | 67 | * Free current thread data structures etc.. |
@@ -153,6 +153,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
153 | save_fp_ctl(&p->thread.fp_regs.fpc); | 153 | save_fp_ctl(&p->thread.fp_regs.fpc); |
154 | save_fp_regs(p->thread.fp_regs.fprs); | 154 | save_fp_regs(p->thread.fp_regs.fprs); |
155 | p->thread.fp_regs.pad = 0; | 155 | p->thread.fp_regs.pad = 0; |
156 | p->thread.vxrs = NULL; | ||
156 | /* Set a new TLS ? */ | 157 | /* Set a new TLS ? */ |
157 | if (clone_flags & CLONE_SETTLS) { | 158 | if (clone_flags & CLONE_SETTLS) { |
158 | unsigned long tls = frame->childregs.gprs[6]; | 159 | unsigned long tls = frame->childregs.gprs[6]; |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 99a567b70d16..eabfb4594517 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -248,14 +248,27 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
248 | */ | 248 | */ |
249 | tmp = 0; | 249 | tmp = 0; |
250 | 250 | ||
251 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
252 | /* | ||
253 | * floating point control reg. is in the thread structure | ||
254 | */ | ||
255 | tmp = child->thread.fp_regs.fpc; | ||
256 | tmp <<= BITS_PER_LONG - 32; | ||
257 | |||
251 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 258 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
252 | /* | 259 | /* |
253 | * floating point regs. are stored in the thread structure | 260 | * floating point regs. are either in child->thread.fp_regs |
261 | * or the child->thread.vxrs array | ||
254 | */ | 262 | */ |
255 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 263 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
256 | tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); | 264 | #ifdef CONFIG_64BIT |
257 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 265 | if (child->thread.vxrs) |
258 | tmp <<= BITS_PER_LONG - 32; | 266 | tmp = *(addr_t *) |
267 | ((addr_t) child->thread.vxrs + 2*offset); | ||
268 | else | ||
269 | #endif | ||
270 | tmp = *(addr_t *) | ||
271 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
259 | 272 | ||
260 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 273 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
261 | /* | 274 | /* |
@@ -383,16 +396,29 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
383 | */ | 396 | */ |
384 | return 0; | 397 | return 0; |
385 | 398 | ||
399 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
400 | /* | ||
401 | * floating point control reg. is in the thread structure | ||
402 | */ | ||
403 | if ((unsigned int) data != 0 || | ||
404 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | ||
405 | return -EINVAL; | ||
406 | child->thread.fp_regs.fpc = data >> (BITS_PER_LONG - 32); | ||
407 | |||
386 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 408 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
387 | /* | 409 | /* |
388 | * floating point regs. are stored in the thread structure | 410 | * floating point regs. are either in child->thread.fp_regs |
411 | * or the child->thread.vxrs array | ||
389 | */ | 412 | */ |
390 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 413 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
391 | if ((unsigned int) data != 0 || | 414 | #ifdef CONFIG_64BIT |
392 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | 415 | if (child->thread.vxrs) |
393 | return -EINVAL; | 416 | *(addr_t *)((addr_t) |
394 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 417 | child->thread.vxrs + 2*offset) = data; |
395 | *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; | 418 | else |
419 | #endif | ||
420 | *(addr_t *)((addr_t) | ||
421 | &child->thread.fp_regs.fprs + offset) = data; | ||
396 | 422 | ||
397 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 423 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
398 | /* | 424 | /* |
@@ -611,12 +637,26 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
611 | */ | 637 | */ |
612 | tmp = 0; | 638 | tmp = 0; |
613 | 639 | ||
640 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { | ||
641 | /* | ||
642 | * floating point control reg. is in the thread structure | ||
643 | */ | ||
644 | tmp = child->thread.fp_regs.fpc; | ||
645 | |||
614 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 646 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
615 | /* | 647 | /* |
616 | * floating point regs. are stored in the thread structure | 648 | * floating point regs. are either in child->thread.fp_regs |
649 | * or the child->thread.vxrs array | ||
617 | */ | 650 | */ |
618 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 651 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; |
619 | tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); | 652 | #ifdef CONFIG_64BIT |
653 | if (child->thread.vxrs) | ||
654 | tmp = *(__u32 *) | ||
655 | ((addr_t) child->thread.vxrs + 2*offset); | ||
656 | else | ||
657 | #endif | ||
658 | tmp = *(__u32 *) | ||
659 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
620 | 660 | ||
621 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 661 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
622 | /* | 662 | /* |
@@ -722,15 +762,28 @@ static int __poke_user_compat(struct task_struct *child, | |||
722 | */ | 762 | */ |
723 | return 0; | 763 | return 0; |
724 | 764 | ||
725 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 765 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { |
726 | /* | 766 | /* |
727 | * floating point regs. are stored in the thread structure | 767 | * floating point control reg. is in the thread structure |
728 | */ | 768 | */ |
729 | if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && | 769 | if (test_fp_ctl(tmp)) |
730 | test_fp_ctl(tmp)) | ||
731 | return -EINVAL; | 770 | return -EINVAL; |
732 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 771 | child->thread.fp_regs.fpc = data; |
733 | *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; | 772 | |
773 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | ||
774 | /* | ||
775 | * floating point regs. are either in child->thread.fp_regs | ||
776 | * or the child->thread.vxrs array | ||
777 | */ | ||
778 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; | ||
779 | #ifdef CONFIG_64BIT | ||
780 | if (child->thread.vxrs) | ||
781 | *(__u32 *)((addr_t) | ||
782 | child->thread.vxrs + 2*offset) = tmp; | ||
783 | else | ||
784 | #endif | ||
785 | *(__u32 *)((addr_t) | ||
786 | &child->thread.fp_regs.fprs + offset) = tmp; | ||
734 | 787 | ||
735 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 788 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
736 | /* | 789 | /* |
@@ -1038,12 +1091,6 @@ static int s390_tdb_set(struct task_struct *target, | |||
1038 | return 0; | 1091 | return 0; |
1039 | } | 1092 | } |
1040 | 1093 | ||
1041 | static int s390_vxrs_active(struct task_struct *target, | ||
1042 | const struct user_regset *regset) | ||
1043 | { | ||
1044 | return !!target->thread.vxrs; | ||
1045 | } | ||
1046 | |||
1047 | static int s390_vxrs_low_get(struct task_struct *target, | 1094 | static int s390_vxrs_low_get(struct task_struct *target, |
1048 | const struct user_regset *regset, | 1095 | const struct user_regset *regset, |
1049 | unsigned int pos, unsigned int count, | 1096 | unsigned int pos, unsigned int count, |
@@ -1052,6 +1099,8 @@ static int s390_vxrs_low_get(struct task_struct *target, | |||
1052 | __u64 vxrs[__NUM_VXRS_LOW]; | 1099 | __u64 vxrs[__NUM_VXRS_LOW]; |
1053 | int i; | 1100 | int i; |
1054 | 1101 | ||
1102 | if (!MACHINE_HAS_VX) | ||
1103 | return -ENODEV; | ||
1055 | if (target->thread.vxrs) { | 1104 | if (target->thread.vxrs) { |
1056 | if (target == current) | 1105 | if (target == current) |
1057 | save_vx_regs(target->thread.vxrs); | 1106 | save_vx_regs(target->thread.vxrs); |
@@ -1070,6 +1119,8 @@ static int s390_vxrs_low_set(struct task_struct *target, | |||
1070 | __u64 vxrs[__NUM_VXRS_LOW]; | 1119 | __u64 vxrs[__NUM_VXRS_LOW]; |
1071 | int i, rc; | 1120 | int i, rc; |
1072 | 1121 | ||
1122 | if (!MACHINE_HAS_VX) | ||
1123 | return -ENODEV; | ||
1073 | if (!target->thread.vxrs) { | 1124 | if (!target->thread.vxrs) { |
1074 | rc = alloc_vector_registers(target); | 1125 | rc = alloc_vector_registers(target); |
1075 | if (rc) | 1126 | if (rc) |
@@ -1095,6 +1146,8 @@ static int s390_vxrs_high_get(struct task_struct *target, | |||
1095 | { | 1146 | { |
1096 | __vector128 vxrs[__NUM_VXRS_HIGH]; | 1147 | __vector128 vxrs[__NUM_VXRS_HIGH]; |
1097 | 1148 | ||
1149 | if (!MACHINE_HAS_VX) | ||
1150 | return -ENODEV; | ||
1098 | if (target->thread.vxrs) { | 1151 | if (target->thread.vxrs) { |
1099 | if (target == current) | 1152 | if (target == current) |
1100 | save_vx_regs(target->thread.vxrs); | 1153 | save_vx_regs(target->thread.vxrs); |
@@ -1112,6 +1165,8 @@ static int s390_vxrs_high_set(struct task_struct *target, | |||
1112 | { | 1165 | { |
1113 | int rc; | 1166 | int rc; |
1114 | 1167 | ||
1168 | if (!MACHINE_HAS_VX) | ||
1169 | return -ENODEV; | ||
1115 | if (!target->thread.vxrs) { | 1170 | if (!target->thread.vxrs) { |
1116 | rc = alloc_vector_registers(target); | 1171 | rc = alloc_vector_registers(target); |
1117 | if (rc) | 1172 | if (rc) |
@@ -1196,7 +1251,6 @@ static const struct user_regset s390_regsets[] = { | |||
1196 | .n = __NUM_VXRS_LOW, | 1251 | .n = __NUM_VXRS_LOW, |
1197 | .size = sizeof(__u64), | 1252 | .size = sizeof(__u64), |
1198 | .align = sizeof(__u64), | 1253 | .align = sizeof(__u64), |
1199 | .active = s390_vxrs_active, | ||
1200 | .get = s390_vxrs_low_get, | 1254 | .get = s390_vxrs_low_get, |
1201 | .set = s390_vxrs_low_set, | 1255 | .set = s390_vxrs_low_set, |
1202 | }, | 1256 | }, |
@@ -1205,7 +1259,6 @@ static const struct user_regset s390_regsets[] = { | |||
1205 | .n = __NUM_VXRS_HIGH, | 1259 | .n = __NUM_VXRS_HIGH, |
1206 | .size = sizeof(__vector128), | 1260 | .size = sizeof(__vector128), |
1207 | .align = sizeof(__vector128), | 1261 | .align = sizeof(__vector128), |
1208 | .active = s390_vxrs_active, | ||
1209 | .get = s390_vxrs_high_get, | 1262 | .get = s390_vxrs_high_get, |
1210 | .set = s390_vxrs_high_set, | 1263 | .set = s390_vxrs_high_set, |
1211 | }, | 1264 | }, |
@@ -1419,7 +1472,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1419 | .n = __NUM_VXRS_LOW, | 1472 | .n = __NUM_VXRS_LOW, |
1420 | .size = sizeof(__u64), | 1473 | .size = sizeof(__u64), |
1421 | .align = sizeof(__u64), | 1474 | .align = sizeof(__u64), |
1422 | .active = s390_vxrs_active, | ||
1423 | .get = s390_vxrs_low_get, | 1475 | .get = s390_vxrs_low_get, |
1424 | .set = s390_vxrs_low_set, | 1476 | .set = s390_vxrs_low_set, |
1425 | }, | 1477 | }, |
@@ -1428,7 +1480,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1428 | .n = __NUM_VXRS_HIGH, | 1480 | .n = __NUM_VXRS_HIGH, |
1429 | .size = sizeof(__vector128), | 1481 | .size = sizeof(__vector128), |
1430 | .align = sizeof(__vector128), | 1482 | .align = sizeof(__vector128), |
1431 | .active = s390_vxrs_active, | ||
1432 | .get = s390_vxrs_high_get, | 1483 | .get = s390_vxrs_high_get, |
1433 | .set = s390_vxrs_high_set, | 1484 | .set = s390_vxrs_high_set, |
1434 | }, | 1485 | }, |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index e80d9ff9a56d..4e532c67832f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <linux/ctype.h> | 41 | #include <linux/ctype.h> |
42 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
43 | #include <linux/topology.h> | 43 | #include <linux/topology.h> |
44 | #include <linux/ftrace.h> | ||
45 | #include <linux/kexec.h> | 44 | #include <linux/kexec.h> |
46 | #include <linux/crash_dump.h> | 45 | #include <linux/crash_dump.h> |
47 | #include <linux/memory.h> | 46 | #include <linux/memory.h> |
@@ -356,7 +355,6 @@ static void __init setup_lowcore(void) | |||
356 | lc->steal_timer = S390_lowcore.steal_timer; | 355 | lc->steal_timer = S390_lowcore.steal_timer; |
357 | lc->last_update_timer = S390_lowcore.last_update_timer; | 356 | lc->last_update_timer = S390_lowcore.last_update_timer; |
358 | lc->last_update_clock = S390_lowcore.last_update_clock; | 357 | lc->last_update_clock = S390_lowcore.last_update_clock; |
359 | lc->ftrace_func = S390_lowcore.ftrace_func; | ||
360 | 358 | ||
361 | restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); | 359 | restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); |
362 | restart_stack += ASYNC_SIZE; | 360 | restart_stack += ASYNC_SIZE; |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 0c1a0ff0a558..6a2ac257d98f 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
@@ -371,7 +371,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
371 | restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE; | 371 | restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE; |
372 | } else { | 372 | } else { |
373 | /* Signal frame without vector registers are short ! */ | 373 | /* Signal frame without vector registers are short ! */ |
374 | __u16 __user *svc = (void *) frame + frame_size - 2; | 374 | __u16 __user *svc = (void __user *) frame + frame_size - 2; |
375 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) | 375 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) |
376 | return -EFAULT; | 376 | return -EFAULT; |
377 | restorer = (unsigned long) svc | PSW_ADDR_AMODE; | 377 | restorer = (unsigned long) svc | PSW_ADDR_AMODE; |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 6fd9e60101f1..0b499f5cbe19 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -236,7 +236,6 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) | |||
236 | lc->percpu_offset = __per_cpu_offset[cpu]; | 236 | lc->percpu_offset = __per_cpu_offset[cpu]; |
237 | lc->kernel_asce = S390_lowcore.kernel_asce; | 237 | lc->kernel_asce = S390_lowcore.kernel_asce; |
238 | lc->machine_flags = S390_lowcore.machine_flags; | 238 | lc->machine_flags = S390_lowcore.machine_flags; |
239 | lc->ftrace_func = S390_lowcore.ftrace_func; | ||
240 | lc->user_timer = lc->system_timer = lc->steal_timer = 0; | 239 | lc->user_timer = lc->system_timer = lc->steal_timer = 0; |
241 | __ctl_store(lc->cregs_save_area, 0, 15); | 240 | __ctl_store(lc->cregs_save_area, 0, 15); |
242 | save_access_regs((unsigned int *) lc->access_regs_save_area); | 241 | save_access_regs((unsigned int *) lc->access_regs_save_area); |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9f7087fd58de..a2987243bc76 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -360,3 +360,5 @@ SYSCALL(sys_seccomp,sys_seccomp,compat_sys_seccomp) | |||
360 | SYSCALL(sys_getrandom,sys_getrandom,compat_sys_getrandom) | 360 | SYSCALL(sys_getrandom,sys_getrandom,compat_sys_getrandom) |
361 | SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */ | 361 | SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */ |
362 | SYSCALL(sys_bpf,sys_bpf,compat_sys_bpf) | 362 | SYSCALL(sys_bpf,sys_bpf,compat_sys_bpf) |
363 | SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_write,compat_sys_s390_pci_mmio_write) | ||
364 | SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_read,compat_sys_s390_pci_mmio_read) | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 005d665fe4a5..20660dddb2d6 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -61,10 +61,11 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); | |||
61 | /* | 61 | /* |
62 | * Scheduler clock - returns current time in nanosec units. | 62 | * Scheduler clock - returns current time in nanosec units. |
63 | */ | 63 | */ |
64 | unsigned long long notrace __kprobes sched_clock(void) | 64 | unsigned long long notrace sched_clock(void) |
65 | { | 65 | { |
66 | return tod_to_ns(get_tod_clock_monotonic()); | 66 | return tod_to_ns(get_tod_clock_monotonic()); |
67 | } | 67 | } |
68 | NOKPROBE_SYMBOL(sched_clock); | ||
68 | 69 | ||
69 | /* | 70 | /* |
70 | * Monotonic_clock - returns # of nanoseconds passed since time_init() | 71 | * Monotonic_clock - returns # of nanoseconds passed since time_init() |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 9ff5ecba26ab..f081cf1157c3 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -49,7 +49,8 @@ static inline void report_user_fault(struct pt_regs *regs, int signr) | |||
49 | return; | 49 | return; |
50 | if (!printk_ratelimit()) | 50 | if (!printk_ratelimit()) |
51 | return; | 51 | return; |
52 | printk("User process fault: interruption code 0x%X ", regs->int_code); | 52 | printk("User process fault: interruption code %04x ilc:%d ", |
53 | regs->int_code & 0xffff, regs->int_code >> 17); | ||
53 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); | 54 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); |
54 | printk("\n"); | 55 | printk("\n"); |
55 | show_regs(regs); | 56 | show_regs(regs); |
@@ -87,16 +88,16 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) | |||
87 | } | 88 | } |
88 | } | 89 | } |
89 | 90 | ||
90 | static void __kprobes do_trap(struct pt_regs *regs, int si_signo, int si_code, | 91 | static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) |
91 | char *str) | ||
92 | { | 92 | { |
93 | if (notify_die(DIE_TRAP, str, regs, 0, | 93 | if (notify_die(DIE_TRAP, str, regs, 0, |
94 | regs->int_code, si_signo) == NOTIFY_STOP) | 94 | regs->int_code, si_signo) == NOTIFY_STOP) |
95 | return; | 95 | return; |
96 | do_report_trap(regs, si_signo, si_code, str); | 96 | do_report_trap(regs, si_signo, si_code, str); |
97 | } | 97 | } |
98 | NOKPROBE_SYMBOL(do_trap); | ||
98 | 99 | ||
99 | void __kprobes do_per_trap(struct pt_regs *regs) | 100 | void do_per_trap(struct pt_regs *regs) |
100 | { | 101 | { |
101 | siginfo_t info; | 102 | siginfo_t info; |
102 | 103 | ||
@@ -111,6 +112,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) | |||
111 | (void __force __user *) current->thread.per_event.address; | 112 | (void __force __user *) current->thread.per_event.address; |
112 | force_sig_info(SIGTRAP, &info, current); | 113 | force_sig_info(SIGTRAP, &info, current); |
113 | } | 114 | } |
115 | NOKPROBE_SYMBOL(do_per_trap); | ||
114 | 116 | ||
115 | void default_trap_handler(struct pt_regs *regs) | 117 | void default_trap_handler(struct pt_regs *regs) |
116 | { | 118 | { |
@@ -151,8 +153,6 @@ DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC, | |||
151 | "privileged operation") | 153 | "privileged operation") |
152 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | 154 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, |
153 | "special operation exception") | 155 | "special operation exception") |
154 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | ||
155 | "translation exception") | ||
156 | 156 | ||
157 | #ifdef CONFIG_64BIT | 157 | #ifdef CONFIG_64BIT |
158 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | 158 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, |
@@ -179,7 +179,13 @@ static inline void do_fp_trap(struct pt_regs *regs, int fpc) | |||
179 | do_trap(regs, SIGFPE, si_code, "floating point exception"); | 179 | do_trap(regs, SIGFPE, si_code, "floating point exception"); |
180 | } | 180 | } |
181 | 181 | ||
182 | void __kprobes illegal_op(struct pt_regs *regs) | 182 | void translation_exception(struct pt_regs *regs) |
183 | { | ||
184 | /* May never happen. */ | ||
185 | die(regs, "Translation exception"); | ||
186 | } | ||
187 | |||
188 | void illegal_op(struct pt_regs *regs) | ||
183 | { | 189 | { |
184 | siginfo_t info; | 190 | siginfo_t info; |
185 | __u8 opcode[6]; | 191 | __u8 opcode[6]; |
@@ -252,7 +258,7 @@ void __kprobes illegal_op(struct pt_regs *regs) | |||
252 | if (signal) | 258 | if (signal) |
253 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); | 259 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); |
254 | } | 260 | } |
255 | 261 | NOKPROBE_SYMBOL(illegal_op); | |
256 | 262 | ||
257 | #ifdef CONFIG_MATHEMU | 263 | #ifdef CONFIG_MATHEMU |
258 | void specification_exception(struct pt_regs *regs) | 264 | void specification_exception(struct pt_regs *regs) |
@@ -469,7 +475,7 @@ void space_switch_exception(struct pt_regs *regs) | |||
469 | do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); | 475 | do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); |
470 | } | 476 | } |
471 | 477 | ||
472 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) | 478 | void kernel_stack_overflow(struct pt_regs *regs) |
473 | { | 479 | { |
474 | bust_spinlocks(1); | 480 | bust_spinlocks(1); |
475 | printk("Kernel stack overflow.\n"); | 481 | printk("Kernel stack overflow.\n"); |
@@ -477,6 +483,7 @@ void __kprobes kernel_stack_overflow(struct pt_regs * regs) | |||
477 | bust_spinlocks(0); | 483 | bust_spinlocks(0); |
478 | panic("Corrupt kernel stack, can't continue."); | 484 | panic("Corrupt kernel stack, can't continue."); |
479 | } | 485 | } |
486 | NOKPROBE_SYMBOL(kernel_stack_overflow); | ||
480 | 487 | ||
481 | void __init trap_init(void) | 488 | void __init trap_init(void) |
482 | { | 489 | { |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 55aade49b6d1..6b049ee75a56 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -271,7 +271,7 @@ static int kvm_s390_mem_control(struct kvm *kvm, struct kvm_device_attr *attr) | |||
271 | case KVM_S390_VM_MEM_CLR_CMMA: | 271 | case KVM_S390_VM_MEM_CLR_CMMA: |
272 | mutex_lock(&kvm->lock); | 272 | mutex_lock(&kvm->lock); |
273 | idx = srcu_read_lock(&kvm->srcu); | 273 | idx = srcu_read_lock(&kvm->srcu); |
274 | page_table_reset_pgste(kvm->arch.gmap->mm, 0, TASK_SIZE, false); | 274 | s390_reset_cmma(kvm->arch.gmap->mm); |
275 | srcu_read_unlock(&kvm->srcu, idx); | 275 | srcu_read_unlock(&kvm->srcu, idx); |
276 | mutex_unlock(&kvm->lock); | 276 | mutex_unlock(&kvm->lock); |
277 | ret = 0; | 277 | ret = 0; |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 72bb2dd8b9cd..f47cb0c6d906 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -156,21 +156,25 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu) | |||
156 | return 0; | 156 | return 0; |
157 | } | 157 | } |
158 | 158 | ||
159 | static void __skey_check_enable(struct kvm_vcpu *vcpu) | 159 | static int __skey_check_enable(struct kvm_vcpu *vcpu) |
160 | { | 160 | { |
161 | int rc = 0; | ||
161 | if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE))) | 162 | if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE))) |
162 | return; | 163 | return rc; |
163 | 164 | ||
164 | s390_enable_skey(); | 165 | rc = s390_enable_skey(); |
165 | trace_kvm_s390_skey_related_inst(vcpu); | 166 | trace_kvm_s390_skey_related_inst(vcpu); |
166 | vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); | 167 | vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); |
168 | return rc; | ||
167 | } | 169 | } |
168 | 170 | ||
169 | 171 | ||
170 | static int handle_skey(struct kvm_vcpu *vcpu) | 172 | static int handle_skey(struct kvm_vcpu *vcpu) |
171 | { | 173 | { |
172 | __skey_check_enable(vcpu); | 174 | int rc = __skey_check_enable(vcpu); |
173 | 175 | ||
176 | if (rc) | ||
177 | return rc; | ||
174 | vcpu->stat.instruction_storage_key++; | 178 | vcpu->stat.instruction_storage_key++; |
175 | 179 | ||
176 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | 180 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) |
@@ -683,7 +687,10 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) | |||
683 | } | 687 | } |
684 | 688 | ||
685 | if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { | 689 | if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { |
686 | __skey_check_enable(vcpu); | 690 | int rc = __skey_check_enable(vcpu); |
691 | |||
692 | if (rc) | ||
693 | return rc; | ||
687 | if (set_guest_storage_key(current->mm, useraddr, | 694 | if (set_guest_storage_key(current->mm, useraddr, |
688 | vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, | 695 | vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, |
689 | vcpu->run->s.regs.gprs[reg1] & PFMF_NQ)) | 696 | vcpu->run->s.regs.gprs[reg1] & PFMF_NQ)) |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a2b81d6ce8a5..811937bb90be 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -261,8 +261,8 @@ static inline void report_user_fault(struct pt_regs *regs, long signr) | |||
261 | return; | 261 | return; |
262 | if (!printk_ratelimit()) | 262 | if (!printk_ratelimit()) |
263 | return; | 263 | return; |
264 | printk(KERN_ALERT "User process fault: interruption code 0x%X ", | 264 | printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d", |
265 | regs->int_code); | 265 | regs->int_code & 0xffff, regs->int_code >> 17); |
266 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); | 266 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); |
267 | printk(KERN_CONT "\n"); | 267 | printk(KERN_CONT "\n"); |
268 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", | 268 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", |
@@ -548,7 +548,7 @@ out: | |||
548 | return fault; | 548 | return fault; |
549 | } | 549 | } |
550 | 550 | ||
551 | void __kprobes do_protection_exception(struct pt_regs *regs) | 551 | void do_protection_exception(struct pt_regs *regs) |
552 | { | 552 | { |
553 | unsigned long trans_exc_code; | 553 | unsigned long trans_exc_code; |
554 | int fault; | 554 | int fault; |
@@ -574,8 +574,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs) | |||
574 | if (unlikely(fault)) | 574 | if (unlikely(fault)) |
575 | do_fault_error(regs, fault); | 575 | do_fault_error(regs, fault); |
576 | } | 576 | } |
577 | NOKPROBE_SYMBOL(do_protection_exception); | ||
577 | 578 | ||
578 | void __kprobes do_dat_exception(struct pt_regs *regs) | 579 | void do_dat_exception(struct pt_regs *regs) |
579 | { | 580 | { |
580 | int access, fault; | 581 | int access, fault; |
581 | 582 | ||
@@ -584,6 +585,7 @@ void __kprobes do_dat_exception(struct pt_regs *regs) | |||
584 | if (unlikely(fault)) | 585 | if (unlikely(fault)) |
585 | do_fault_error(regs, fault); | 586 | do_fault_error(regs, fault); |
586 | } | 587 | } |
588 | NOKPROBE_SYMBOL(do_dat_exception); | ||
587 | 589 | ||
588 | #ifdef CONFIG_PFAULT | 590 | #ifdef CONFIG_PFAULT |
589 | /* | 591 | /* |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 1b79ca67392f..71c7eff2c89f 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/swapops.h> | 20 | #include <linux/swapops.h> |
21 | #include <linux/ksm.h> | ||
22 | #include <linux/mman.h> | ||
21 | 23 | ||
22 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
23 | #include <asm/pgalloc.h> | 25 | #include <asm/pgalloc.h> |
@@ -750,8 +752,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | |||
750 | break; | 752 | break; |
751 | /* Walk the process page table, lock and get pte pointer */ | 753 | /* Walk the process page table, lock and get pte pointer */ |
752 | ptep = get_locked_pte(gmap->mm, addr, &ptl); | 754 | ptep = get_locked_pte(gmap->mm, addr, &ptl); |
753 | if (unlikely(!ptep)) | 755 | VM_BUG_ON(!ptep); |
754 | continue; | ||
755 | /* Set notification bit in the pgste of the pte */ | 756 | /* Set notification bit in the pgste of the pte */ |
756 | entry = *ptep; | 757 | entry = *ptep; |
757 | if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { | 758 | if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { |
@@ -761,7 +762,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | |||
761 | gaddr += PAGE_SIZE; | 762 | gaddr += PAGE_SIZE; |
762 | len -= PAGE_SIZE; | 763 | len -= PAGE_SIZE; |
763 | } | 764 | } |
764 | spin_unlock(ptl); | 765 | pte_unmap_unlock(ptep, ptl); |
765 | } | 766 | } |
766 | up_read(&gmap->mm->mmap_sem); | 767 | up_read(&gmap->mm->mmap_sem); |
767 | return rc; | 768 | return rc; |
@@ -834,99 +835,6 @@ static inline void page_table_free_pgste(unsigned long *table) | |||
834 | __free_page(page); | 835 | __free_page(page); |
835 | } | 836 | } |
836 | 837 | ||
837 | static inline unsigned long page_table_reset_pte(struct mm_struct *mm, pmd_t *pmd, | ||
838 | unsigned long addr, unsigned long end, bool init_skey) | ||
839 | { | ||
840 | pte_t *start_pte, *pte; | ||
841 | spinlock_t *ptl; | ||
842 | pgste_t pgste; | ||
843 | |||
844 | start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl); | ||
845 | pte = start_pte; | ||
846 | do { | ||
847 | pgste = pgste_get_lock(pte); | ||
848 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
849 | if (init_skey) { | ||
850 | unsigned long address; | ||
851 | |||
852 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | | ||
853 | PGSTE_GR_BIT | PGSTE_GC_BIT); | ||
854 | |||
855 | /* skip invalid and not writable pages */ | ||
856 | if (pte_val(*pte) & _PAGE_INVALID || | ||
857 | !(pte_val(*pte) & _PAGE_WRITE)) { | ||
858 | pgste_set_unlock(pte, pgste); | ||
859 | continue; | ||
860 | } | ||
861 | |||
862 | address = pte_val(*pte) & PAGE_MASK; | ||
863 | page_set_storage_key(address, PAGE_DEFAULT_KEY, 1); | ||
864 | } | ||
865 | pgste_set_unlock(pte, pgste); | ||
866 | } while (pte++, addr += PAGE_SIZE, addr != end); | ||
867 | pte_unmap_unlock(start_pte, ptl); | ||
868 | |||
869 | return addr; | ||
870 | } | ||
871 | |||
872 | static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, pud_t *pud, | ||
873 | unsigned long addr, unsigned long end, bool init_skey) | ||
874 | { | ||
875 | unsigned long next; | ||
876 | pmd_t *pmd; | ||
877 | |||
878 | pmd = pmd_offset(pud, addr); | ||
879 | do { | ||
880 | next = pmd_addr_end(addr, end); | ||
881 | if (pmd_none_or_clear_bad(pmd)) | ||
882 | continue; | ||
883 | next = page_table_reset_pte(mm, pmd, addr, next, init_skey); | ||
884 | } while (pmd++, addr = next, addr != end); | ||
885 | |||
886 | return addr; | ||
887 | } | ||
888 | |||
889 | static inline unsigned long page_table_reset_pud(struct mm_struct *mm, pgd_t *pgd, | ||
890 | unsigned long addr, unsigned long end, bool init_skey) | ||
891 | { | ||
892 | unsigned long next; | ||
893 | pud_t *pud; | ||
894 | |||
895 | pud = pud_offset(pgd, addr); | ||
896 | do { | ||
897 | next = pud_addr_end(addr, end); | ||
898 | if (pud_none_or_clear_bad(pud)) | ||
899 | continue; | ||
900 | next = page_table_reset_pmd(mm, pud, addr, next, init_skey); | ||
901 | } while (pud++, addr = next, addr != end); | ||
902 | |||
903 | return addr; | ||
904 | } | ||
905 | |||
906 | void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | ||
907 | unsigned long end, bool init_skey) | ||
908 | { | ||
909 | unsigned long addr, next; | ||
910 | pgd_t *pgd; | ||
911 | |||
912 | down_write(&mm->mmap_sem); | ||
913 | if (init_skey && mm_use_skey(mm)) | ||
914 | goto out_up; | ||
915 | addr = start; | ||
916 | pgd = pgd_offset(mm, addr); | ||
917 | do { | ||
918 | next = pgd_addr_end(addr, end); | ||
919 | if (pgd_none_or_clear_bad(pgd)) | ||
920 | continue; | ||
921 | next = page_table_reset_pud(mm, pgd, addr, next, init_skey); | ||
922 | } while (pgd++, addr = next, addr != end); | ||
923 | if (init_skey) | ||
924 | current->mm->context.use_skey = 1; | ||
925 | out_up: | ||
926 | up_write(&mm->mmap_sem); | ||
927 | } | ||
928 | EXPORT_SYMBOL(page_table_reset_pgste); | ||
929 | |||
930 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 838 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
931 | unsigned long key, bool nq) | 839 | unsigned long key, bool nq) |
932 | { | 840 | { |
@@ -992,11 +900,6 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm) | |||
992 | return NULL; | 900 | return NULL; |
993 | } | 901 | } |
994 | 902 | ||
995 | void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | ||
996 | unsigned long end, bool init_skey) | ||
997 | { | ||
998 | } | ||
999 | |||
1000 | static inline void page_table_free_pgste(unsigned long *table) | 903 | static inline void page_table_free_pgste(unsigned long *table) |
1001 | { | 904 | { |
1002 | } | 905 | } |
@@ -1347,13 +1250,89 @@ EXPORT_SYMBOL_GPL(s390_enable_sie); | |||
1347 | * Enable storage key handling from now on and initialize the storage | 1250 | * Enable storage key handling from now on and initialize the storage |
1348 | * keys with the default key. | 1251 | * keys with the default key. |
1349 | */ | 1252 | */ |
1350 | void s390_enable_skey(void) | 1253 | static int __s390_enable_skey(pte_t *pte, unsigned long addr, |
1254 | unsigned long next, struct mm_walk *walk) | ||
1351 | { | 1255 | { |
1352 | page_table_reset_pgste(current->mm, 0, TASK_SIZE, true); | 1256 | unsigned long ptev; |
1257 | pgste_t pgste; | ||
1258 | |||
1259 | pgste = pgste_get_lock(pte); | ||
1260 | /* | ||
1261 | * Remove all zero page mappings, | ||
1262 | * after establishing a policy to forbid zero page mappings | ||
1263 | * following faults for that page will get fresh anonymous pages | ||
1264 | */ | ||
1265 | if (is_zero_pfn(pte_pfn(*pte))) { | ||
1266 | ptep_flush_direct(walk->mm, addr, pte); | ||
1267 | pte_val(*pte) = _PAGE_INVALID; | ||
1268 | } | ||
1269 | /* Clear storage key */ | ||
1270 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | | ||
1271 | PGSTE_GR_BIT | PGSTE_GC_BIT); | ||
1272 | ptev = pte_val(*pte); | ||
1273 | if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) | ||
1274 | page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); | ||
1275 | pgste_set_unlock(pte, pgste); | ||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | int s390_enable_skey(void) | ||
1280 | { | ||
1281 | struct mm_walk walk = { .pte_entry = __s390_enable_skey }; | ||
1282 | struct mm_struct *mm = current->mm; | ||
1283 | struct vm_area_struct *vma; | ||
1284 | int rc = 0; | ||
1285 | |||
1286 | down_write(&mm->mmap_sem); | ||
1287 | if (mm_use_skey(mm)) | ||
1288 | goto out_up; | ||
1289 | |||
1290 | mm->context.use_skey = 1; | ||
1291 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
1292 | if (ksm_madvise(vma, vma->vm_start, vma->vm_end, | ||
1293 | MADV_UNMERGEABLE, &vma->vm_flags)) { | ||
1294 | mm->context.use_skey = 0; | ||
1295 | rc = -ENOMEM; | ||
1296 | goto out_up; | ||
1297 | } | ||
1298 | } | ||
1299 | mm->def_flags &= ~VM_MERGEABLE; | ||
1300 | |||
1301 | walk.mm = mm; | ||
1302 | walk_page_range(0, TASK_SIZE, &walk); | ||
1303 | |||
1304 | out_up: | ||
1305 | up_write(&mm->mmap_sem); | ||
1306 | return rc; | ||
1353 | } | 1307 | } |
1354 | EXPORT_SYMBOL_GPL(s390_enable_skey); | 1308 | EXPORT_SYMBOL_GPL(s390_enable_skey); |
1355 | 1309 | ||
1356 | /* | 1310 | /* |
1311 | * Reset CMMA state, make all pages stable again. | ||
1312 | */ | ||
1313 | static int __s390_reset_cmma(pte_t *pte, unsigned long addr, | ||
1314 | unsigned long next, struct mm_walk *walk) | ||
1315 | { | ||
1316 | pgste_t pgste; | ||
1317 | |||
1318 | pgste = pgste_get_lock(pte); | ||
1319 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
1320 | pgste_set_unlock(pte, pgste); | ||
1321 | return 0; | ||
1322 | } | ||
1323 | |||
1324 | void s390_reset_cmma(struct mm_struct *mm) | ||
1325 | { | ||
1326 | struct mm_walk walk = { .pte_entry = __s390_reset_cmma }; | ||
1327 | |||
1328 | down_write(&mm->mmap_sem); | ||
1329 | walk.mm = mm; | ||
1330 | walk_page_range(0, TASK_SIZE, &walk); | ||
1331 | up_write(&mm->mmap_sem); | ||
1332 | } | ||
1333 | EXPORT_SYMBOL_GPL(s390_reset_cmma); | ||
1334 | |||
1335 | /* | ||
1357 | * Test and reset if a guest page is dirty | 1336 | * Test and reset if a guest page is dirty |
1358 | */ | 1337 | */ |
1359 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) | 1338 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) |
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile index a9e1dc4ae442..805d8b29193a 100644 --- a/arch/s390/pci/Makefile +++ b/arch/s390/pci/Makefile | |||
@@ -3,4 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_sysfs.o \ | 5 | obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_sysfs.o \ |
6 | pci_event.o pci_debug.o pci_insn.o | 6 | pci_event.o pci_debug.o pci_insn.o pci_mmio.o |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index d59c82569750..3290f11ae1d9 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -369,8 +369,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
369 | 369 | ||
370 | if (type == PCI_CAP_ID_MSI && nvec > 1) | 370 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
371 | return 1; | 371 | return 1; |
372 | msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX); | 372 | msi_vecs = min_t(unsigned int, nvec, zdev->max_msi); |
373 | msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI); | ||
374 | 373 | ||
375 | /* Allocate adapter summary indicator bit */ | 374 | /* Allocate adapter summary indicator bit */ |
376 | rc = -EIO; | 375 | rc = -EIO; |
@@ -474,7 +473,8 @@ static void zpci_map_resources(struct zpci_dev *zdev) | |||
474 | len = pci_resource_len(pdev, i); | 473 | len = pci_resource_len(pdev, i); |
475 | if (!len) | 474 | if (!len) |
476 | continue; | 475 | continue; |
477 | pdev->resource[i].start = (resource_size_t) pci_iomap(pdev, i, 0); | 476 | pdev->resource[i].start = |
477 | (resource_size_t __force) pci_iomap(pdev, i, 0); | ||
478 | pdev->resource[i].end = pdev->resource[i].start + len - 1; | 478 | pdev->resource[i].end = pdev->resource[i].start + len - 1; |
479 | } | 479 | } |
480 | } | 480 | } |
@@ -489,7 +489,8 @@ static void zpci_unmap_resources(struct zpci_dev *zdev) | |||
489 | len = pci_resource_len(pdev, i); | 489 | len = pci_resource_len(pdev, i); |
490 | if (!len) | 490 | if (!len) |
491 | continue; | 491 | continue; |
492 | pci_iounmap(pdev, (void *) pdev->resource[i].start); | 492 | pci_iounmap(pdev, (void __iomem __force *) |
493 | pdev->resource[i].start); | ||
493 | } | 494 | } |
494 | } | 495 | } |
495 | 496 | ||
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 6e22a247de9b..d6e411ed8b1f 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
@@ -62,6 +62,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev, | |||
62 | zdev->tlb_refresh = response->refresh; | 62 | zdev->tlb_refresh = response->refresh; |
63 | zdev->dma_mask = response->dasm; | 63 | zdev->dma_mask = response->dasm; |
64 | zdev->msi_addr = response->msia; | 64 | zdev->msi_addr = response->msia; |
65 | zdev->max_msi = response->noi; | ||
65 | zdev->fmb_update = response->mui; | 66 | zdev->fmb_update = response->mui; |
66 | 67 | ||
67 | switch (response->version) { | 68 | switch (response->version) { |
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index eec598c5939f..3229a2e570df 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c | |||
@@ -158,10 +158,7 @@ int __init zpci_debug_init(void) | |||
158 | 158 | ||
159 | void zpci_debug_exit(void) | 159 | void zpci_debug_exit(void) |
160 | { | 160 | { |
161 | if (pci_debug_msg_id) | 161 | debug_unregister(pci_debug_msg_id); |
162 | debug_unregister(pci_debug_msg_id); | 162 | debug_unregister(pci_debug_err_id); |
163 | if (pci_debug_err_id) | ||
164 | debug_unregister(pci_debug_err_id); | ||
165 | |||
166 | debugfs_remove(debugfs_root); | 163 | debugfs_remove(debugfs_root); |
167 | } | 164 | } |
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c new file mode 100644 index 000000000000..62c5ea6d8682 --- /dev/null +++ b/arch/s390/pci/pci_mmio.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Access to PCI I/O memory from user space programs. | ||
3 | * | ||
4 | * Copyright IBM Corp. 2014 | ||
5 | * Author(s): Alexey Ishchuk <aishchuk@linux.vnet.ibm.com> | ||
6 | */ | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/syscalls.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/pci.h> | ||
13 | |||
14 | static long get_pfn(unsigned long user_addr, unsigned long access, | ||
15 | unsigned long *pfn) | ||
16 | { | ||
17 | struct vm_area_struct *vma; | ||
18 | long ret; | ||
19 | |||
20 | down_read(¤t->mm->mmap_sem); | ||
21 | ret = -EINVAL; | ||
22 | vma = find_vma(current->mm, user_addr); | ||
23 | if (!vma) | ||
24 | goto out; | ||
25 | ret = -EACCES; | ||
26 | if (!(vma->vm_flags & access)) | ||
27 | goto out; | ||
28 | ret = follow_pfn(vma, user_addr, pfn); | ||
29 | out: | ||
30 | up_read(¤t->mm->mmap_sem); | ||
31 | return ret; | ||
32 | } | ||
33 | |||
34 | SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, | ||
35 | const void __user *, user_buffer, size_t, length) | ||
36 | { | ||
37 | u8 local_buf[64]; | ||
38 | void __iomem *io_addr; | ||
39 | void *buf; | ||
40 | unsigned long pfn; | ||
41 | long ret; | ||
42 | |||
43 | if (!zpci_is_enabled()) | ||
44 | return -ENODEV; | ||
45 | |||
46 | if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length) | ||
47 | return -EINVAL; | ||
48 | if (length > 64) { | ||
49 | buf = kmalloc(length, GFP_KERNEL); | ||
50 | if (!buf) | ||
51 | return -ENOMEM; | ||
52 | } else | ||
53 | buf = local_buf; | ||
54 | |||
55 | ret = get_pfn(mmio_addr, VM_WRITE, &pfn); | ||
56 | if (ret) | ||
57 | goto out; | ||
58 | io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); | ||
59 | |||
60 | ret = -EFAULT; | ||
61 | if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) | ||
62 | goto out; | ||
63 | |||
64 | if (copy_from_user(buf, user_buffer, length)) | ||
65 | goto out; | ||
66 | |||
67 | memcpy_toio(io_addr, buf, length); | ||
68 | ret = 0; | ||
69 | out: | ||
70 | if (buf != local_buf) | ||
71 | kfree(buf); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, | ||
76 | void __user *, user_buffer, size_t, length) | ||
77 | { | ||
78 | u8 local_buf[64]; | ||
79 | void __iomem *io_addr; | ||
80 | void *buf; | ||
81 | unsigned long pfn; | ||
82 | long ret; | ||
83 | |||
84 | if (!zpci_is_enabled()) | ||
85 | return -ENODEV; | ||
86 | |||
87 | if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length) | ||
88 | return -EINVAL; | ||
89 | if (length > 64) { | ||
90 | buf = kmalloc(length, GFP_KERNEL); | ||
91 | if (!buf) | ||
92 | return -ENOMEM; | ||
93 | } else | ||
94 | buf = local_buf; | ||
95 | |||
96 | ret = get_pfn(mmio_addr, VM_READ, &pfn); | ||
97 | if (ret) | ||
98 | goto out; | ||
99 | io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); | ||
100 | |||
101 | ret = -EFAULT; | ||
102 | if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) | ||
103 | goto out; | ||
104 | |||
105 | memcpy_fromio(buf, io_addr, length); | ||
106 | |||
107 | if (copy_to_user(user_buffer, buf, length)) | ||
108 | goto out; | ||
109 | |||
110 | ret = 0; | ||
111 | out: | ||
112 | if (buf != local_buf) | ||
113 | kfree(buf); | ||
114 | return ret; | ||
115 | } | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 329db997ee66..4abf11965484 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -1377,6 +1377,20 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) | |||
1377 | "I/O error, retry"); | 1377 | "I/O error, retry"); |
1378 | break; | 1378 | break; |
1379 | case -EINVAL: | 1379 | case -EINVAL: |
1380 | /* | ||
1381 | * device not valid so no I/O could be running | ||
1382 | * handle CQR as termination successful | ||
1383 | */ | ||
1384 | cqr->status = DASD_CQR_CLEARED; | ||
1385 | cqr->stopclk = get_tod_clock(); | ||
1386 | cqr->starttime = 0; | ||
1387 | /* no retries for invalid devices */ | ||
1388 | cqr->retries = -1; | ||
1389 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
1390 | "EINVAL, handle as terminated"); | ||
1391 | /* fake rc to success */ | ||
1392 | rc = 0; | ||
1393 | break; | ||
1380 | case -EBUSY: | 1394 | case -EBUSY: |
1381 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | 1395 | DBF_DEV_EVENT(DBF_ERR, device, "%s", |
1382 | "device busy, retry later"); | 1396 | "device busy, retry later"); |
@@ -1683,11 +1697,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1683 | if (cqr->status == DASD_CQR_CLEAR_PENDING && | 1697 | if (cqr->status == DASD_CQR_CLEAR_PENDING && |
1684 | scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { | 1698 | scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { |
1685 | cqr->status = DASD_CQR_CLEARED; | 1699 | cqr->status = DASD_CQR_CLEARED; |
1686 | if (cqr->callback_data == DASD_SLEEPON_START_TAG) | ||
1687 | cqr->callback_data = DASD_SLEEPON_END_TAG; | ||
1688 | dasd_device_clear_timer(device); | 1700 | dasd_device_clear_timer(device); |
1689 | wake_up(&dasd_flush_wq); | 1701 | wake_up(&dasd_flush_wq); |
1690 | wake_up(&generic_waitq); | ||
1691 | dasd_schedule_device_bh(device); | 1702 | dasd_schedule_device_bh(device); |
1692 | return; | 1703 | return; |
1693 | } | 1704 | } |
@@ -2326,21 +2337,11 @@ retry: | |||
2326 | return -EAGAIN; | 2337 | return -EAGAIN; |
2327 | 2338 | ||
2328 | /* normal recovery for basedev IO */ | 2339 | /* normal recovery for basedev IO */ |
2329 | if (__dasd_sleep_on_erp(cqr)) { | 2340 | if (__dasd_sleep_on_erp(cqr)) |
2341 | /* handle erp first */ | ||
2330 | goto retry; | 2342 | goto retry; |
2331 | /* remember that ERP was needed */ | ||
2332 | rc = 1; | ||
2333 | /* skip processing for active cqr */ | ||
2334 | if (cqr->status != DASD_CQR_TERMINATED && | ||
2335 | cqr->status != DASD_CQR_NEED_ERP) | ||
2336 | break; | ||
2337 | } | ||
2338 | } | 2343 | } |
2339 | 2344 | ||
2340 | /* start ERP requests in upper loop */ | ||
2341 | if (rc) | ||
2342 | goto retry; | ||
2343 | |||
2344 | return 0; | 2345 | return 0; |
2345 | } | 2346 | } |
2346 | 2347 | ||
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index f224d59c4b6b..90f39f79f5d7 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
@@ -99,15 +99,37 @@ void dasd_gendisk_free(struct dasd_block *block) | |||
99 | int dasd_scan_partitions(struct dasd_block *block) | 99 | int dasd_scan_partitions(struct dasd_block *block) |
100 | { | 100 | { |
101 | struct block_device *bdev; | 101 | struct block_device *bdev; |
102 | int retry, rc; | ||
102 | 103 | ||
104 | retry = 5; | ||
103 | bdev = bdget_disk(block->gdp, 0); | 105 | bdev = bdget_disk(block->gdp, 0); |
104 | if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0) | 106 | if (!bdev) { |
107 | DBF_DEV_EVENT(DBF_ERR, block->base, "%s", | ||
108 | "scan partitions error, bdget returned NULL"); | ||
105 | return -ENODEV; | 109 | return -ENODEV; |
110 | } | ||
111 | |||
112 | rc = blkdev_get(bdev, FMODE_READ, NULL); | ||
113 | if (rc < 0) { | ||
114 | DBF_DEV_EVENT(DBF_ERR, block->base, | ||
115 | "scan partitions error, blkdev_get returned %d", | ||
116 | rc); | ||
117 | return -ENODEV; | ||
118 | } | ||
106 | /* | 119 | /* |
107 | * See fs/partition/check.c:register_disk,rescan_partitions | 120 | * See fs/partition/check.c:register_disk,rescan_partitions |
108 | * Can't call rescan_partitions directly. Use ioctl. | 121 | * Can't call rescan_partitions directly. Use ioctl. |
109 | */ | 122 | */ |
110 | ioctl_by_bdev(bdev, BLKRRPART, 0); | 123 | rc = ioctl_by_bdev(bdev, BLKRRPART, 0); |
124 | while (rc == -EBUSY && retry > 0) { | ||
125 | schedule(); | ||
126 | rc = ioctl_by_bdev(bdev, BLKRRPART, 0); | ||
127 | retry--; | ||
128 | DBF_DEV_EVENT(DBF_ERR, block->base, | ||
129 | "scan partitions error, retry %d rc %d", | ||
130 | retry, rc); | ||
131 | } | ||
132 | |||
111 | /* | 133 | /* |
112 | * Since the matching blkdev_put call to the blkdev_get in | 134 | * Since the matching blkdev_put call to the blkdev_get in |
113 | * this function is not called before dasd_destroy_partitions | 135 | * this function is not called before dasd_destroy_partitions |
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 56046ab39629..75d9896deccb 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/mempool.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/blkdev.h> | 15 | #include <linux/blkdev.h> |
15 | #include <linux/genhd.h> | 16 | #include <linux/genhd.h> |
@@ -20,13 +21,18 @@ | |||
20 | 21 | ||
21 | debug_info_t *scm_debug; | 22 | debug_info_t *scm_debug; |
22 | static int scm_major; | 23 | static int scm_major; |
24 | static mempool_t *aidaw_pool; | ||
23 | static DEFINE_SPINLOCK(list_lock); | 25 | static DEFINE_SPINLOCK(list_lock); |
24 | static LIST_HEAD(inactive_requests); | 26 | static LIST_HEAD(inactive_requests); |
25 | static unsigned int nr_requests = 64; | 27 | static unsigned int nr_requests = 64; |
28 | static unsigned int nr_requests_per_io = 8; | ||
26 | static atomic_t nr_devices = ATOMIC_INIT(0); | 29 | static atomic_t nr_devices = ATOMIC_INIT(0); |
27 | module_param(nr_requests, uint, S_IRUGO); | 30 | module_param(nr_requests, uint, S_IRUGO); |
28 | MODULE_PARM_DESC(nr_requests, "Number of parallel requests."); | 31 | MODULE_PARM_DESC(nr_requests, "Number of parallel requests."); |
29 | 32 | ||
33 | module_param(nr_requests_per_io, uint, S_IRUGO); | ||
34 | MODULE_PARM_DESC(nr_requests_per_io, "Number of requests per IO."); | ||
35 | |||
30 | MODULE_DESCRIPTION("Block driver for s390 storage class memory."); | 36 | MODULE_DESCRIPTION("Block driver for s390 storage class memory."); |
31 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
32 | MODULE_ALIAS("scm:scmdev*"); | 38 | MODULE_ALIAS("scm:scmdev*"); |
@@ -36,8 +42,8 @@ static void __scm_free_rq(struct scm_request *scmrq) | |||
36 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | 42 | struct aob_rq_header *aobrq = to_aobrq(scmrq); |
37 | 43 | ||
38 | free_page((unsigned long) scmrq->aob); | 44 | free_page((unsigned long) scmrq->aob); |
39 | free_page((unsigned long) scmrq->aidaw); | ||
40 | __scm_free_rq_cluster(scmrq); | 45 | __scm_free_rq_cluster(scmrq); |
46 | kfree(scmrq->request); | ||
41 | kfree(aobrq); | 47 | kfree(aobrq); |
42 | } | 48 | } |
43 | 49 | ||
@@ -53,6 +59,8 @@ static void scm_free_rqs(void) | |||
53 | __scm_free_rq(scmrq); | 59 | __scm_free_rq(scmrq); |
54 | } | 60 | } |
55 | spin_unlock_irq(&list_lock); | 61 | spin_unlock_irq(&list_lock); |
62 | |||
63 | mempool_destroy(aidaw_pool); | ||
56 | } | 64 | } |
57 | 65 | ||
58 | static int __scm_alloc_rq(void) | 66 | static int __scm_alloc_rq(void) |
@@ -65,17 +73,17 @@ static int __scm_alloc_rq(void) | |||
65 | return -ENOMEM; | 73 | return -ENOMEM; |
66 | 74 | ||
67 | scmrq = (void *) aobrq->data; | 75 | scmrq = (void *) aobrq->data; |
68 | scmrq->aidaw = (void *) get_zeroed_page(GFP_DMA); | ||
69 | scmrq->aob = (void *) get_zeroed_page(GFP_DMA); | 76 | scmrq->aob = (void *) get_zeroed_page(GFP_DMA); |
70 | if (!scmrq->aob || !scmrq->aidaw) { | 77 | if (!scmrq->aob) |
71 | __scm_free_rq(scmrq); | 78 | goto free; |
72 | return -ENOMEM; | ||
73 | } | ||
74 | 79 | ||
75 | if (__scm_alloc_rq_cluster(scmrq)) { | 80 | scmrq->request = kcalloc(nr_requests_per_io, sizeof(scmrq->request[0]), |
76 | __scm_free_rq(scmrq); | 81 | GFP_KERNEL); |
77 | return -ENOMEM; | 82 | if (!scmrq->request) |
78 | } | 83 | goto free; |
84 | |||
85 | if (__scm_alloc_rq_cluster(scmrq)) | ||
86 | goto free; | ||
79 | 87 | ||
80 | INIT_LIST_HEAD(&scmrq->list); | 88 | INIT_LIST_HEAD(&scmrq->list); |
81 | spin_lock_irq(&list_lock); | 89 | spin_lock_irq(&list_lock); |
@@ -83,12 +91,19 @@ static int __scm_alloc_rq(void) | |||
83 | spin_unlock_irq(&list_lock); | 91 | spin_unlock_irq(&list_lock); |
84 | 92 | ||
85 | return 0; | 93 | return 0; |
94 | free: | ||
95 | __scm_free_rq(scmrq); | ||
96 | return -ENOMEM; | ||
86 | } | 97 | } |
87 | 98 | ||
88 | static int scm_alloc_rqs(unsigned int nrqs) | 99 | static int scm_alloc_rqs(unsigned int nrqs) |
89 | { | 100 | { |
90 | int ret = 0; | 101 | int ret = 0; |
91 | 102 | ||
103 | aidaw_pool = mempool_create_page_pool(max(nrqs/8, 1U), 0); | ||
104 | if (!aidaw_pool) | ||
105 | return -ENOMEM; | ||
106 | |||
92 | while (nrqs-- && !ret) | 107 | while (nrqs-- && !ret) |
93 | ret = __scm_alloc_rq(); | 108 | ret = __scm_alloc_rq(); |
94 | 109 | ||
@@ -112,6 +127,18 @@ out: | |||
112 | static void scm_request_done(struct scm_request *scmrq) | 127 | static void scm_request_done(struct scm_request *scmrq) |
113 | { | 128 | { |
114 | unsigned long flags; | 129 | unsigned long flags; |
130 | struct msb *msb; | ||
131 | u64 aidaw; | ||
132 | int i; | ||
133 | |||
134 | for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) { | ||
135 | msb = &scmrq->aob->msb[i]; | ||
136 | aidaw = msb->data_addr; | ||
137 | |||
138 | if ((msb->flags & MSB_FLAG_IDA) && aidaw && | ||
139 | IS_ALIGNED(aidaw, PAGE_SIZE)) | ||
140 | mempool_free(virt_to_page(aidaw), aidaw_pool); | ||
141 | } | ||
115 | 142 | ||
116 | spin_lock_irqsave(&list_lock, flags); | 143 | spin_lock_irqsave(&list_lock, flags); |
117 | list_add(&scmrq->list, &inactive_requests); | 144 | list_add(&scmrq->list, &inactive_requests); |
@@ -123,48 +150,90 @@ static bool scm_permit_request(struct scm_blk_dev *bdev, struct request *req) | |||
123 | return rq_data_dir(req) != WRITE || bdev->state != SCM_WR_PROHIBIT; | 150 | return rq_data_dir(req) != WRITE || bdev->state != SCM_WR_PROHIBIT; |
124 | } | 151 | } |
125 | 152 | ||
126 | static void scm_request_prepare(struct scm_request *scmrq) | 153 | static inline struct aidaw *scm_aidaw_alloc(void) |
154 | { | ||
155 | struct page *page = mempool_alloc(aidaw_pool, GFP_ATOMIC); | ||
156 | |||
157 | return page ? page_address(page) : NULL; | ||
158 | } | ||
159 | |||
160 | static inline unsigned long scm_aidaw_bytes(struct aidaw *aidaw) | ||
161 | { | ||
162 | unsigned long _aidaw = (unsigned long) aidaw; | ||
163 | unsigned long bytes = ALIGN(_aidaw, PAGE_SIZE) - _aidaw; | ||
164 | |||
165 | return (bytes / sizeof(*aidaw)) * PAGE_SIZE; | ||
166 | } | ||
167 | |||
168 | struct aidaw *scm_aidaw_fetch(struct scm_request *scmrq, unsigned int bytes) | ||
169 | { | ||
170 | struct aidaw *aidaw; | ||
171 | |||
172 | if (scm_aidaw_bytes(scmrq->next_aidaw) >= bytes) | ||
173 | return scmrq->next_aidaw; | ||
174 | |||
175 | aidaw = scm_aidaw_alloc(); | ||
176 | if (aidaw) | ||
177 | memset(aidaw, 0, PAGE_SIZE); | ||
178 | return aidaw; | ||
179 | } | ||
180 | |||
181 | static int scm_request_prepare(struct scm_request *scmrq) | ||
127 | { | 182 | { |
128 | struct scm_blk_dev *bdev = scmrq->bdev; | 183 | struct scm_blk_dev *bdev = scmrq->bdev; |
129 | struct scm_device *scmdev = bdev->gendisk->private_data; | 184 | struct scm_device *scmdev = bdev->gendisk->private_data; |
130 | struct aidaw *aidaw = scmrq->aidaw; | 185 | int pos = scmrq->aob->request.msb_count; |
131 | struct msb *msb = &scmrq->aob->msb[0]; | 186 | struct msb *msb = &scmrq->aob->msb[pos]; |
187 | struct request *req = scmrq->request[pos]; | ||
132 | struct req_iterator iter; | 188 | struct req_iterator iter; |
189 | struct aidaw *aidaw; | ||
133 | struct bio_vec bv; | 190 | struct bio_vec bv; |
134 | 191 | ||
192 | aidaw = scm_aidaw_fetch(scmrq, blk_rq_bytes(req)); | ||
193 | if (!aidaw) | ||
194 | return -ENOMEM; | ||
195 | |||
135 | msb->bs = MSB_BS_4K; | 196 | msb->bs = MSB_BS_4K; |
136 | scmrq->aob->request.msb_count = 1; | 197 | scmrq->aob->request.msb_count++; |
137 | msb->scm_addr = scmdev->address + | 198 | msb->scm_addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); |
138 | ((u64) blk_rq_pos(scmrq->request) << 9); | 199 | msb->oc = (rq_data_dir(req) == READ) ? MSB_OC_READ : MSB_OC_WRITE; |
139 | msb->oc = (rq_data_dir(scmrq->request) == READ) ? | ||
140 | MSB_OC_READ : MSB_OC_WRITE; | ||
141 | msb->flags |= MSB_FLAG_IDA; | 200 | msb->flags |= MSB_FLAG_IDA; |
142 | msb->data_addr = (u64) aidaw; | 201 | msb->data_addr = (u64) aidaw; |
143 | 202 | ||
144 | rq_for_each_segment(bv, scmrq->request, iter) { | 203 | rq_for_each_segment(bv, req, iter) { |
145 | WARN_ON(bv.bv_offset); | 204 | WARN_ON(bv.bv_offset); |
146 | msb->blk_count += bv.bv_len >> 12; | 205 | msb->blk_count += bv.bv_len >> 12; |
147 | aidaw->data_addr = (u64) page_address(bv.bv_page); | 206 | aidaw->data_addr = (u64) page_address(bv.bv_page); |
148 | aidaw++; | 207 | aidaw++; |
149 | } | 208 | } |
209 | |||
210 | scmrq->next_aidaw = aidaw; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static inline void scm_request_set(struct scm_request *scmrq, | ||
215 | struct request *req) | ||
216 | { | ||
217 | scmrq->request[scmrq->aob->request.msb_count] = req; | ||
150 | } | 218 | } |
151 | 219 | ||
152 | static inline void scm_request_init(struct scm_blk_dev *bdev, | 220 | static inline void scm_request_init(struct scm_blk_dev *bdev, |
153 | struct scm_request *scmrq, | 221 | struct scm_request *scmrq) |
154 | struct request *req) | ||
155 | { | 222 | { |
156 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | 223 | struct aob_rq_header *aobrq = to_aobrq(scmrq); |
157 | struct aob *aob = scmrq->aob; | 224 | struct aob *aob = scmrq->aob; |
158 | 225 | ||
226 | memset(scmrq->request, 0, | ||
227 | nr_requests_per_io * sizeof(scmrq->request[0])); | ||
159 | memset(aob, 0, sizeof(*aob)); | 228 | memset(aob, 0, sizeof(*aob)); |
160 | memset(scmrq->aidaw, 0, PAGE_SIZE); | ||
161 | aobrq->scmdev = bdev->scmdev; | 229 | aobrq->scmdev = bdev->scmdev; |
162 | aob->request.cmd_code = ARQB_CMD_MOVE; | 230 | aob->request.cmd_code = ARQB_CMD_MOVE; |
163 | aob->request.data = (u64) aobrq; | 231 | aob->request.data = (u64) aobrq; |
164 | scmrq->request = req; | ||
165 | scmrq->bdev = bdev; | 232 | scmrq->bdev = bdev; |
166 | scmrq->retries = 4; | 233 | scmrq->retries = 4; |
167 | scmrq->error = 0; | 234 | scmrq->error = 0; |
235 | /* We don't use all msbs - place aidaws at the end of the aob page. */ | ||
236 | scmrq->next_aidaw = (void *) &aob->msb[nr_requests_per_io]; | ||
168 | scm_request_cluster_init(scmrq); | 237 | scm_request_cluster_init(scmrq); |
169 | } | 238 | } |
170 | 239 | ||
@@ -180,9 +249,12 @@ static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) | |||
180 | void scm_request_requeue(struct scm_request *scmrq) | 249 | void scm_request_requeue(struct scm_request *scmrq) |
181 | { | 250 | { |
182 | struct scm_blk_dev *bdev = scmrq->bdev; | 251 | struct scm_blk_dev *bdev = scmrq->bdev; |
252 | int i; | ||
183 | 253 | ||
184 | scm_release_cluster(scmrq); | 254 | scm_release_cluster(scmrq); |
185 | blk_requeue_request(bdev->rq, scmrq->request); | 255 | for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) |
256 | blk_requeue_request(bdev->rq, scmrq->request[i]); | ||
257 | |||
186 | atomic_dec(&bdev->queued_reqs); | 258 | atomic_dec(&bdev->queued_reqs); |
187 | scm_request_done(scmrq); | 259 | scm_request_done(scmrq); |
188 | scm_ensure_queue_restart(bdev); | 260 | scm_ensure_queue_restart(bdev); |
@@ -191,20 +263,41 @@ void scm_request_requeue(struct scm_request *scmrq) | |||
191 | void scm_request_finish(struct scm_request *scmrq) | 263 | void scm_request_finish(struct scm_request *scmrq) |
192 | { | 264 | { |
193 | struct scm_blk_dev *bdev = scmrq->bdev; | 265 | struct scm_blk_dev *bdev = scmrq->bdev; |
266 | int i; | ||
194 | 267 | ||
195 | scm_release_cluster(scmrq); | 268 | scm_release_cluster(scmrq); |
196 | blk_end_request_all(scmrq->request, scmrq->error); | 269 | for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) |
270 | blk_end_request_all(scmrq->request[i], scmrq->error); | ||
271 | |||
197 | atomic_dec(&bdev->queued_reqs); | 272 | atomic_dec(&bdev->queued_reqs); |
198 | scm_request_done(scmrq); | 273 | scm_request_done(scmrq); |
199 | } | 274 | } |
200 | 275 | ||
276 | static int scm_request_start(struct scm_request *scmrq) | ||
277 | { | ||
278 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
279 | int ret; | ||
280 | |||
281 | atomic_inc(&bdev->queued_reqs); | ||
282 | if (!scmrq->aob->request.msb_count) { | ||
283 | scm_request_requeue(scmrq); | ||
284 | return -EINVAL; | ||
285 | } | ||
286 | |||
287 | ret = eadm_start_aob(scmrq->aob); | ||
288 | if (ret) { | ||
289 | SCM_LOG(5, "no subchannel"); | ||
290 | scm_request_requeue(scmrq); | ||
291 | } | ||
292 | return ret; | ||
293 | } | ||
294 | |||
201 | static void scm_blk_request(struct request_queue *rq) | 295 | static void scm_blk_request(struct request_queue *rq) |
202 | { | 296 | { |
203 | struct scm_device *scmdev = rq->queuedata; | 297 | struct scm_device *scmdev = rq->queuedata; |
204 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); | 298 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); |
205 | struct scm_request *scmrq; | 299 | struct scm_request *scmrq = NULL; |
206 | struct request *req; | 300 | struct request *req; |
207 | int ret; | ||
208 | 301 | ||
209 | while ((req = blk_peek_request(rq))) { | 302 | while ((req = blk_peek_request(rq))) { |
210 | if (req->cmd_type != REQ_TYPE_FS) { | 303 | if (req->cmd_type != REQ_TYPE_FS) { |
@@ -214,39 +307,64 @@ static void scm_blk_request(struct request_queue *rq) | |||
214 | continue; | 307 | continue; |
215 | } | 308 | } |
216 | 309 | ||
217 | if (!scm_permit_request(bdev, req)) { | 310 | if (!scm_permit_request(bdev, req)) |
218 | scm_ensure_queue_restart(bdev); | 311 | goto out; |
219 | return; | 312 | |
220 | } | ||
221 | scmrq = scm_request_fetch(); | ||
222 | if (!scmrq) { | 313 | if (!scmrq) { |
223 | SCM_LOG(5, "no request"); | 314 | scmrq = scm_request_fetch(); |
224 | scm_ensure_queue_restart(bdev); | 315 | if (!scmrq) { |
225 | return; | 316 | SCM_LOG(5, "no request"); |
317 | goto out; | ||
318 | } | ||
319 | scm_request_init(bdev, scmrq); | ||
226 | } | 320 | } |
227 | scm_request_init(bdev, scmrq, req); | 321 | scm_request_set(scmrq, req); |
322 | |||
228 | if (!scm_reserve_cluster(scmrq)) { | 323 | if (!scm_reserve_cluster(scmrq)) { |
229 | SCM_LOG(5, "cluster busy"); | 324 | SCM_LOG(5, "cluster busy"); |
325 | scm_request_set(scmrq, NULL); | ||
326 | if (scmrq->aob->request.msb_count) | ||
327 | goto out; | ||
328 | |||
230 | scm_request_done(scmrq); | 329 | scm_request_done(scmrq); |
231 | return; | 330 | return; |
232 | } | 331 | } |
332 | |||
233 | if (scm_need_cluster_request(scmrq)) { | 333 | if (scm_need_cluster_request(scmrq)) { |
234 | atomic_inc(&bdev->queued_reqs); | 334 | if (scmrq->aob->request.msb_count) { |
235 | blk_start_request(req); | 335 | /* Start cluster requests separately. */ |
236 | scm_initiate_cluster_request(scmrq); | 336 | scm_request_set(scmrq, NULL); |
237 | return; | 337 | if (scm_request_start(scmrq)) |
338 | return; | ||
339 | } else { | ||
340 | atomic_inc(&bdev->queued_reqs); | ||
341 | blk_start_request(req); | ||
342 | scm_initiate_cluster_request(scmrq); | ||
343 | } | ||
344 | scmrq = NULL; | ||
345 | continue; | ||
346 | } | ||
347 | |||
348 | if (scm_request_prepare(scmrq)) { | ||
349 | SCM_LOG(5, "aidaw alloc failed"); | ||
350 | scm_request_set(scmrq, NULL); | ||
351 | goto out; | ||
238 | } | 352 | } |
239 | scm_request_prepare(scmrq); | ||
240 | atomic_inc(&bdev->queued_reqs); | ||
241 | blk_start_request(req); | 353 | blk_start_request(req); |
242 | 354 | ||
243 | ret = eadm_start_aob(scmrq->aob); | 355 | if (scmrq->aob->request.msb_count < nr_requests_per_io) |
244 | if (ret) { | 356 | continue; |
245 | SCM_LOG(5, "no subchannel"); | 357 | |
246 | scm_request_requeue(scmrq); | 358 | if (scm_request_start(scmrq)) |
247 | return; | 359 | return; |
248 | } | 360 | |
361 | scmrq = NULL; | ||
249 | } | 362 | } |
363 | out: | ||
364 | if (scmrq) | ||
365 | scm_request_start(scmrq); | ||
366 | else | ||
367 | scm_ensure_queue_restart(bdev); | ||
250 | } | 368 | } |
251 | 369 | ||
252 | static void __scmrq_log_error(struct scm_request *scmrq) | 370 | static void __scmrq_log_error(struct scm_request *scmrq) |
@@ -443,11 +561,19 @@ void scm_blk_set_available(struct scm_blk_dev *bdev) | |||
443 | spin_unlock_irqrestore(&bdev->lock, flags); | 561 | spin_unlock_irqrestore(&bdev->lock, flags); |
444 | } | 562 | } |
445 | 563 | ||
564 | static bool __init scm_blk_params_valid(void) | ||
565 | { | ||
566 | if (!nr_requests_per_io || nr_requests_per_io > 64) | ||
567 | return false; | ||
568 | |||
569 | return scm_cluster_size_valid(); | ||
570 | } | ||
571 | |||
446 | static int __init scm_blk_init(void) | 572 | static int __init scm_blk_init(void) |
447 | { | 573 | { |
448 | int ret = -EINVAL; | 574 | int ret = -EINVAL; |
449 | 575 | ||
450 | if (!scm_cluster_size_valid()) | 576 | if (!scm_blk_params_valid()) |
451 | goto out; | 577 | goto out; |
452 | 578 | ||
453 | ret = register_blkdev(0, "scm"); | 579 | ret = register_blkdev(0, "scm"); |
diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h index e59331e6c2e5..09218cdc5129 100644 --- a/drivers/s390/block/scm_blk.h +++ b/drivers/s390/block/scm_blk.h | |||
@@ -30,8 +30,8 @@ struct scm_blk_dev { | |||
30 | 30 | ||
31 | struct scm_request { | 31 | struct scm_request { |
32 | struct scm_blk_dev *bdev; | 32 | struct scm_blk_dev *bdev; |
33 | struct request *request; | 33 | struct aidaw *next_aidaw; |
34 | struct aidaw *aidaw; | 34 | struct request **request; |
35 | struct aob *aob; | 35 | struct aob *aob; |
36 | struct list_head list; | 36 | struct list_head list; |
37 | u8 retries; | 37 | u8 retries; |
@@ -55,6 +55,8 @@ void scm_blk_irq(struct scm_device *, void *, int); | |||
55 | void scm_request_finish(struct scm_request *); | 55 | void scm_request_finish(struct scm_request *); |
56 | void scm_request_requeue(struct scm_request *); | 56 | void scm_request_requeue(struct scm_request *); |
57 | 57 | ||
58 | struct aidaw *scm_aidaw_fetch(struct scm_request *scmrq, unsigned int bytes); | ||
59 | |||
58 | int scm_drv_init(void); | 60 | int scm_drv_init(void); |
59 | void scm_drv_cleanup(void); | 61 | void scm_drv_cleanup(void); |
60 | 62 | ||
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c index 9aae909d47a5..09db45296eed 100644 --- a/drivers/s390/block/scm_blk_cluster.c +++ b/drivers/s390/block/scm_blk_cluster.c | |||
@@ -57,39 +57,52 @@ void scm_request_cluster_init(struct scm_request *scmrq) | |||
57 | scmrq->cluster.state = CLUSTER_NONE; | 57 | scmrq->cluster.state = CLUSTER_NONE; |
58 | } | 58 | } |
59 | 59 | ||
60 | static bool clusters_intersect(struct scm_request *A, struct scm_request *B) | 60 | static bool clusters_intersect(struct request *A, struct request *B) |
61 | { | 61 | { |
62 | unsigned long firstA, lastA, firstB, lastB; | 62 | unsigned long firstA, lastA, firstB, lastB; |
63 | 63 | ||
64 | firstA = ((u64) blk_rq_pos(A->request) << 9) / CLUSTER_SIZE; | 64 | firstA = ((u64) blk_rq_pos(A) << 9) / CLUSTER_SIZE; |
65 | lastA = (((u64) blk_rq_pos(A->request) << 9) + | 65 | lastA = (((u64) blk_rq_pos(A) << 9) + |
66 | blk_rq_bytes(A->request) - 1) / CLUSTER_SIZE; | 66 | blk_rq_bytes(A) - 1) / CLUSTER_SIZE; |
67 | 67 | ||
68 | firstB = ((u64) blk_rq_pos(B->request) << 9) / CLUSTER_SIZE; | 68 | firstB = ((u64) blk_rq_pos(B) << 9) / CLUSTER_SIZE; |
69 | lastB = (((u64) blk_rq_pos(B->request) << 9) + | 69 | lastB = (((u64) blk_rq_pos(B) << 9) + |
70 | blk_rq_bytes(B->request) - 1) / CLUSTER_SIZE; | 70 | blk_rq_bytes(B) - 1) / CLUSTER_SIZE; |
71 | 71 | ||
72 | return (firstB <= lastA && firstA <= lastB); | 72 | return (firstB <= lastA && firstA <= lastB); |
73 | } | 73 | } |
74 | 74 | ||
75 | bool scm_reserve_cluster(struct scm_request *scmrq) | 75 | bool scm_reserve_cluster(struct scm_request *scmrq) |
76 | { | 76 | { |
77 | struct request *req = scmrq->request[scmrq->aob->request.msb_count]; | ||
77 | struct scm_blk_dev *bdev = scmrq->bdev; | 78 | struct scm_blk_dev *bdev = scmrq->bdev; |
78 | struct scm_request *iter; | 79 | struct scm_request *iter; |
80 | int pos, add = 1; | ||
79 | 81 | ||
80 | if (write_cluster_size == 0) | 82 | if (write_cluster_size == 0) |
81 | return true; | 83 | return true; |
82 | 84 | ||
83 | spin_lock(&bdev->lock); | 85 | spin_lock(&bdev->lock); |
84 | list_for_each_entry(iter, &bdev->cluster_list, cluster.list) { | 86 | list_for_each_entry(iter, &bdev->cluster_list, cluster.list) { |
85 | if (clusters_intersect(scmrq, iter) && | 87 | if (iter == scmrq) { |
86 | (rq_data_dir(scmrq->request) == WRITE || | 88 | /* |
87 | rq_data_dir(iter->request) == WRITE)) { | 89 | * We don't have to use clusters_intersect here, since |
88 | spin_unlock(&bdev->lock); | 90 | * cluster requests are always started separately. |
89 | return false; | 91 | */ |
92 | add = 0; | ||
93 | continue; | ||
94 | } | ||
95 | for (pos = 0; pos <= iter->aob->request.msb_count; pos++) { | ||
96 | if (clusters_intersect(req, iter->request[pos]) && | ||
97 | (rq_data_dir(req) == WRITE || | ||
98 | rq_data_dir(iter->request[pos]) == WRITE)) { | ||
99 | spin_unlock(&bdev->lock); | ||
100 | return false; | ||
101 | } | ||
90 | } | 102 | } |
91 | } | 103 | } |
92 | list_add(&scmrq->cluster.list, &bdev->cluster_list); | 104 | if (add) |
105 | list_add(&scmrq->cluster.list, &bdev->cluster_list); | ||
93 | spin_unlock(&bdev->lock); | 106 | spin_unlock(&bdev->lock); |
94 | 107 | ||
95 | return true; | 108 | return true; |
@@ -114,14 +127,14 @@ void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) | |||
114 | blk_queue_io_opt(bdev->rq, CLUSTER_SIZE); | 127 | blk_queue_io_opt(bdev->rq, CLUSTER_SIZE); |
115 | } | 128 | } |
116 | 129 | ||
117 | static void scm_prepare_cluster_request(struct scm_request *scmrq) | 130 | static int scm_prepare_cluster_request(struct scm_request *scmrq) |
118 | { | 131 | { |
119 | struct scm_blk_dev *bdev = scmrq->bdev; | 132 | struct scm_blk_dev *bdev = scmrq->bdev; |
120 | struct scm_device *scmdev = bdev->gendisk->private_data; | 133 | struct scm_device *scmdev = bdev->gendisk->private_data; |
121 | struct request *req = scmrq->request; | 134 | struct request *req = scmrq->request[0]; |
122 | struct aidaw *aidaw = scmrq->aidaw; | ||
123 | struct msb *msb = &scmrq->aob->msb[0]; | 135 | struct msb *msb = &scmrq->aob->msb[0]; |
124 | struct req_iterator iter; | 136 | struct req_iterator iter; |
137 | struct aidaw *aidaw; | ||
125 | struct bio_vec bv; | 138 | struct bio_vec bv; |
126 | int i = 0; | 139 | int i = 0; |
127 | u64 addr; | 140 | u64 addr; |
@@ -131,11 +144,9 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) | |||
131 | scmrq->cluster.state = CLUSTER_READ; | 144 | scmrq->cluster.state = CLUSTER_READ; |
132 | /* fall through */ | 145 | /* fall through */ |
133 | case CLUSTER_READ: | 146 | case CLUSTER_READ: |
134 | scmrq->aob->request.msb_count = 1; | ||
135 | msb->bs = MSB_BS_4K; | 147 | msb->bs = MSB_BS_4K; |
136 | msb->oc = MSB_OC_READ; | 148 | msb->oc = MSB_OC_READ; |
137 | msb->flags = MSB_FLAG_IDA; | 149 | msb->flags = MSB_FLAG_IDA; |
138 | msb->data_addr = (u64) aidaw; | ||
139 | msb->blk_count = write_cluster_size; | 150 | msb->blk_count = write_cluster_size; |
140 | 151 | ||
141 | addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); | 152 | addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); |
@@ -146,6 +157,12 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) | |||
146 | CLUSTER_SIZE)) | 157 | CLUSTER_SIZE)) |
147 | msb->blk_count = 2 * write_cluster_size; | 158 | msb->blk_count = 2 * write_cluster_size; |
148 | 159 | ||
160 | aidaw = scm_aidaw_fetch(scmrq, msb->blk_count * PAGE_SIZE); | ||
161 | if (!aidaw) | ||
162 | return -ENOMEM; | ||
163 | |||
164 | scmrq->aob->request.msb_count = 1; | ||
165 | msb->data_addr = (u64) aidaw; | ||
149 | for (i = 0; i < msb->blk_count; i++) { | 166 | for (i = 0; i < msb->blk_count; i++) { |
150 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | 167 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; |
151 | aidaw++; | 168 | aidaw++; |
@@ -153,6 +170,7 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) | |||
153 | 170 | ||
154 | break; | 171 | break; |
155 | case CLUSTER_WRITE: | 172 | case CLUSTER_WRITE: |
173 | aidaw = (void *) msb->data_addr; | ||
156 | msb->oc = MSB_OC_WRITE; | 174 | msb->oc = MSB_OC_WRITE; |
157 | 175 | ||
158 | for (addr = msb->scm_addr; | 176 | for (addr = msb->scm_addr; |
@@ -173,22 +191,29 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) | |||
173 | } | 191 | } |
174 | break; | 192 | break; |
175 | } | 193 | } |
194 | return 0; | ||
176 | } | 195 | } |
177 | 196 | ||
178 | bool scm_need_cluster_request(struct scm_request *scmrq) | 197 | bool scm_need_cluster_request(struct scm_request *scmrq) |
179 | { | 198 | { |
180 | if (rq_data_dir(scmrq->request) == READ) | 199 | int pos = scmrq->aob->request.msb_count; |
200 | |||
201 | if (rq_data_dir(scmrq->request[pos]) == READ) | ||
181 | return false; | 202 | return false; |
182 | 203 | ||
183 | return blk_rq_bytes(scmrq->request) < CLUSTER_SIZE; | 204 | return blk_rq_bytes(scmrq->request[pos]) < CLUSTER_SIZE; |
184 | } | 205 | } |
185 | 206 | ||
186 | /* Called with queue lock held. */ | 207 | /* Called with queue lock held. */ |
187 | void scm_initiate_cluster_request(struct scm_request *scmrq) | 208 | void scm_initiate_cluster_request(struct scm_request *scmrq) |
188 | { | 209 | { |
189 | scm_prepare_cluster_request(scmrq); | 210 | if (scm_prepare_cluster_request(scmrq)) |
211 | goto requeue; | ||
190 | if (eadm_start_aob(scmrq->aob)) | 212 | if (eadm_start_aob(scmrq->aob)) |
191 | scm_request_requeue(scmrq); | 213 | goto requeue; |
214 | return; | ||
215 | requeue: | ||
216 | scm_request_requeue(scmrq); | ||
192 | } | 217 | } |
193 | 218 | ||
194 | bool scm_test_cluster_request(struct scm_request *scmrq) | 219 | bool scm_test_cluster_request(struct scm_request *scmrq) |
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index db2cb1f8a1b5..a5c6f7e157aa 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig | |||
@@ -102,6 +102,16 @@ config SCLP_ASYNC | |||
102 | want for inform other people about your kernel panics, | 102 | want for inform other people about your kernel panics, |
103 | need this feature and intend to run your kernel in LPAR. | 103 | need this feature and intend to run your kernel in LPAR. |
104 | 104 | ||
105 | config SCLP_ASYNC_ID | ||
106 | string "Component ID for Call Home" | ||
107 | depends on SCLP_ASYNC | ||
108 | default "000000000" | ||
109 | help | ||
110 | The Component ID for Call Home is used to identify the correct | ||
111 | problem reporting queue the call home records should be sent to. | ||
112 | |||
113 | If your are unsure, please use the default value "000000000". | ||
114 | |||
105 | config HMC_DRV | 115 | config HMC_DRV |
106 | def_tristate m | 116 | def_tristate m |
107 | prompt "Support for file transfers from HMC drive CD/DVD-ROM" | 117 | prompt "Support for file transfers from HMC drive CD/DVD-ROM" |
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c index 5f9f929e891c..19c25427f27f 100644 --- a/drivers/s390/char/sclp_async.c +++ b/drivers/s390/char/sclp_async.c | |||
@@ -137,7 +137,8 @@ static int sclp_async_send_wait(char *message) | |||
137 | * Retain Queue | 137 | * Retain Queue |
138 | * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) | 138 | * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) |
139 | */ | 139 | */ |
140 | strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id)); | 140 | strncpy(sccb->evbuf.comp_id, CONFIG_SCLP_ASYNC_ID, |
141 | sizeof(sccb->evbuf.comp_id)); | ||
141 | sccb->evbuf.header.length = sizeof(sccb->evbuf); | 142 | sccb->evbuf.header.length = sizeof(sccb->evbuf); |
142 | sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); | 143 | sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); |
143 | sccb->header.function_code = SCLP_NORMAL_WRITE; | 144 | sccb->header.function_code = SCLP_NORMAL_WRITE; |
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 37f0834300ea..bee8c11cd086 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c | |||
@@ -31,7 +31,7 @@ | |||
31 | MODULE_DESCRIPTION("driver for s390 eadm subchannels"); | 31 | MODULE_DESCRIPTION("driver for s390 eadm subchannels"); |
32 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
33 | 33 | ||
34 | #define EADM_TIMEOUT (5 * HZ) | 34 | #define EADM_TIMEOUT (7 * HZ) |
35 | static DEFINE_SPINLOCK(list_lock); | 35 | static DEFINE_SPINLOCK(list_lock); |
36 | static LIST_HEAD(eadm_list); | 36 | static LIST_HEAD(eadm_list); |
37 | 37 | ||
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 752e30d63904..177d5973b132 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h | |||
@@ -103,6 +103,17 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, | |||
103 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 103 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
104 | #endif | 104 | #endif |
105 | 105 | ||
106 | #ifndef __HAVE_ARCH_PMDP_GET_AND_CLEAR_FULL | ||
107 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
108 | static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm, | ||
109 | unsigned long address, pmd_t *pmdp, | ||
110 | int full) | ||
111 | { | ||
112 | return pmdp_get_and_clear(mm, address, pmdp); | ||
113 | } | ||
114 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | ||
115 | #endif | ||
116 | |||
106 | #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | 117 | #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL |
107 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | 118 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, |
108 | unsigned long address, pte_t *ptep, | 119 | unsigned long address, pte_t *ptep, |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index f7296e57d614..5297f9fa0ef2 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -335,6 +335,7 @@ extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | |||
335 | extern int arch_prepare_kprobe_ftrace(struct kprobe *p); | 335 | extern int arch_prepare_kprobe_ftrace(struct kprobe *p); |
336 | #endif | 336 | #endif |
337 | 337 | ||
338 | int arch_check_ftrace_location(struct kprobe *p); | ||
338 | 339 | ||
339 | /* Get the kprobe at this addr (if any) - called with preemption disabled */ | 340 | /* Get the kprobe at this addr (if any) - called with preemption disabled */ |
340 | struct kprobe *get_kprobe(void *addr); | 341 | struct kprobe *get_kprobe(void *addr); |
diff --git a/include/linux/mm.h b/include/linux/mm.h index f7606d3a0915..3b337efbe533 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -56,6 +56,17 @@ extern int sysctl_legacy_va_layout; | |||
56 | #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) | 56 | #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) |
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | /* | ||
60 | * To prevent common memory management code establishing | ||
61 | * a zero page mapping on a read fault. | ||
62 | * This macro should be defined within <asm/pgtable.h>. | ||
63 | * s390 does this to prevent multiplexing of hardware bits | ||
64 | * related to the physical page in case of virtualization. | ||
65 | */ | ||
66 | #ifndef mm_forbids_zeropage | ||
67 | #define mm_forbids_zeropage(X) (0) | ||
68 | #endif | ||
69 | |||
59 | extern unsigned long sysctl_user_reserve_kbytes; | 70 | extern unsigned long sysctl_user_reserve_kbytes; |
60 | extern unsigned long sysctl_admin_reserve_kbytes; | 71 | extern unsigned long sysctl_admin_reserve_kbytes; |
61 | 72 | ||
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 831978cebf1d..06f58309fed2 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -1410,16 +1410,10 @@ static inline int check_kprobe_rereg(struct kprobe *p) | |||
1410 | return ret; | 1410 | return ret; |
1411 | } | 1411 | } |
1412 | 1412 | ||
1413 | static int check_kprobe_address_safe(struct kprobe *p, | 1413 | int __weak arch_check_ftrace_location(struct kprobe *p) |
1414 | struct module **probed_mod) | ||
1415 | { | 1414 | { |
1416 | int ret = 0; | ||
1417 | unsigned long ftrace_addr; | 1415 | unsigned long ftrace_addr; |
1418 | 1416 | ||
1419 | /* | ||
1420 | * If the address is located on a ftrace nop, set the | ||
1421 | * breakpoint to the following instruction. | ||
1422 | */ | ||
1423 | ftrace_addr = ftrace_location((unsigned long)p->addr); | 1417 | ftrace_addr = ftrace_location((unsigned long)p->addr); |
1424 | if (ftrace_addr) { | 1418 | if (ftrace_addr) { |
1425 | #ifdef CONFIG_KPROBES_ON_FTRACE | 1419 | #ifdef CONFIG_KPROBES_ON_FTRACE |
@@ -1431,7 +1425,17 @@ static int check_kprobe_address_safe(struct kprobe *p, | |||
1431 | return -EINVAL; | 1425 | return -EINVAL; |
1432 | #endif | 1426 | #endif |
1433 | } | 1427 | } |
1428 | return 0; | ||
1429 | } | ||
1434 | 1430 | ||
1431 | static int check_kprobe_address_safe(struct kprobe *p, | ||
1432 | struct module **probed_mod) | ||
1433 | { | ||
1434 | int ret; | ||
1435 | |||
1436 | ret = arch_check_ftrace_location(p); | ||
1437 | if (ret) | ||
1438 | return ret; | ||
1435 | jump_label_lock(); | 1439 | jump_label_lock(); |
1436 | preempt_disable(); | 1440 | preempt_disable(); |
1437 | 1441 | ||
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 02aa4185b17e..61eea02b53f5 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -169,6 +169,8 @@ cond_syscall(ppc_rtas); | |||
169 | cond_syscall(sys_spu_run); | 169 | cond_syscall(sys_spu_run); |
170 | cond_syscall(sys_spu_create); | 170 | cond_syscall(sys_spu_create); |
171 | cond_syscall(sys_subpage_prot); | 171 | cond_syscall(sys_subpage_prot); |
172 | cond_syscall(sys_s390_pci_mmio_read); | ||
173 | cond_syscall(sys_s390_pci_mmio_write); | ||
172 | 174 | ||
173 | /* mmu depending weak syscall entries */ | 175 | /* mmu depending weak syscall entries */ |
174 | cond_syscall(sys_mprotect); | 176 | cond_syscall(sys_mprotect); |
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 5b2c6875fc38..46f96c23cc27 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -804,7 +804,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
804 | return VM_FAULT_OOM; | 804 | return VM_FAULT_OOM; |
805 | if (unlikely(khugepaged_enter(vma, vma->vm_flags))) | 805 | if (unlikely(khugepaged_enter(vma, vma->vm_flags))) |
806 | return VM_FAULT_OOM; | 806 | return VM_FAULT_OOM; |
807 | if (!(flags & FAULT_FLAG_WRITE) && | 807 | if (!(flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(mm) && |
808 | transparent_hugepage_use_zero_page()) { | 808 | transparent_hugepage_use_zero_page()) { |
809 | spinlock_t *ptl; | 809 | spinlock_t *ptl; |
810 | pgtable_t pgtable; | 810 | pgtable_t pgtable; |
@@ -1399,7 +1399,8 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, | |||
1399 | * pgtable_trans_huge_withdraw after finishing pmdp related | 1399 | * pgtable_trans_huge_withdraw after finishing pmdp related |
1400 | * operations. | 1400 | * operations. |
1401 | */ | 1401 | */ |
1402 | orig_pmd = pmdp_get_and_clear(tlb->mm, addr, pmd); | 1402 | orig_pmd = pmdp_get_and_clear_full(tlb->mm, addr, pmd, |
1403 | tlb->fullmm); | ||
1403 | tlb_remove_pmd_tlb_entry(tlb, pmd, addr); | 1404 | tlb_remove_pmd_tlb_entry(tlb, pmd, addr); |
1404 | pgtable = pgtable_trans_huge_withdraw(tlb->mm, pmd); | 1405 | pgtable = pgtable_trans_huge_withdraw(tlb->mm, pmd); |
1405 | if (is_huge_zero_pmd(orig_pmd)) { | 1406 | if (is_huge_zero_pmd(orig_pmd)) { |
diff --git a/mm/memory.c b/mm/memory.c index 0b3f6c71620d..4b5a282e1107 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -2627,7 +2627,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2627 | return VM_FAULT_SIGBUS; | 2627 | return VM_FAULT_SIGBUS; |
2628 | 2628 | ||
2629 | /* Use the zero-page for reads */ | 2629 | /* Use the zero-page for reads */ |
2630 | if (!(flags & FAULT_FLAG_WRITE)) { | 2630 | if (!(flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(mm)) { |
2631 | entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), | 2631 | entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), |
2632 | vma->vm_page_prot)); | 2632 | vma->vm_page_prot)); |
2633 | page_table = pte_offset_map_lock(mm, pmd, address, &ptl); | 2633 | page_table = pte_offset_map_lock(mm, pmd, address, &ptl); |
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 001facfa5b74..3d1984e59a30 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c | |||
@@ -404,7 +404,7 @@ do_file(char const *const fname) | |||
404 | } | 404 | } |
405 | if (w2(ghdr->e_machine) == EM_S390) { | 405 | if (w2(ghdr->e_machine) == EM_S390) { |
406 | reltype = R_390_64; | 406 | reltype = R_390_64; |
407 | mcount_adjust_64 = -8; | 407 | mcount_adjust_64 = -14; |
408 | } | 408 | } |
409 | if (w2(ghdr->e_machine) == EM_MIPS) { | 409 | if (w2(ghdr->e_machine) == EM_MIPS) { |
410 | reltype = R_MIPS_64; | 410 | reltype = R_MIPS_64; |
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index d4b665610d67..56ea99a12ab7 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -243,7 +243,7 @@ if ($arch eq "x86_64") { | |||
243 | 243 | ||
244 | } elsif ($arch eq "s390" && $bits == 64) { | 244 | } elsif ($arch eq "s390" && $bits == 64) { |
245 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; | 245 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; |
246 | $mcount_adjust = -8; | 246 | $mcount_adjust = -14; |
247 | $alignment = 8; | 247 | $alignment = 8; |
248 | $type = ".quad"; | 248 | $type = ".quad"; |
249 | $ld .= " -m elf64_s390"; | 249 | $ld .= " -m elf64_s390"; |