diff options
-rw-r--r-- | arch/s390/kernel/entry.S | 102 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 97 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 46 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 13 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 13 | ||||
-rw-r--r-- | drivers/s390/s390mach.c | 321 | ||||
-rw-r--r-- | drivers/s390/s390mach.h | 35 | ||||
-rw-r--r-- | include/asm-s390/lowcore.h | 7 | ||||
-rw-r--r-- | include/asm-s390/processor.h | 52 | ||||
-rw-r--r-- | include/asm-s390/ptrace.h | 2 | ||||
-rw-r--r-- | include/asm-s390/system.h | 21 | ||||
-rw-r--r-- | include/asm-s390/thread_info.h | 2 |
12 files changed, 576 insertions, 135 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index c0e09b33febe..5b262b5d869f 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -7,6 +7,7 @@ | |||
7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | 7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), |
8 | * Hartmut Penner (hp@de.ibm.com), | 8 | * Hartmut Penner (hp@de.ibm.com), |
9 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 9 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), |
10 | * Heiko Carstens <heiko.carstens@de.ibm.com> | ||
10 | */ | 11 | */ |
11 | 12 | ||
12 | #include <linux/sys.h> | 13 | #include <linux/sys.h> |
@@ -49,9 +50,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC | |||
49 | SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP | 50 | SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP |
50 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | 51 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE |
51 | 52 | ||
52 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 53 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \ |
53 | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) | 54 | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) |
54 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) | 55 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) |
55 | 56 | ||
56 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 57 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
57 | STACK_SIZE = 1 << STACK_SHIFT | 58 | STACK_SIZE = 1 << STACK_SHIFT |
@@ -121,7 +122,11 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
121 | bz BASED(stack_overflow) | 122 | bz BASED(stack_overflow) |
122 | 3: | 123 | 3: |
123 | #endif | 124 | #endif |
124 | 2: s %r15,BASED(.Lc_spsize) # make room for registers & psw | 125 | 2: |
126 | .endm | ||
127 | |||
128 | .macro CREATE_STACK_FRAME psworg,savearea | ||
129 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | ||
125 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack | 130 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack |
126 | la %r12,\psworg | 131 | la %r12,\psworg |
127 | st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | 132 | st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 |
@@ -161,6 +166,13 @@ __switch_to_base: | |||
161 | be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's | 166 | be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's |
162 | lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't | 167 | lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't |
163 | __switch_to_noper: | 168 | __switch_to_noper: |
169 | l %r4,__THREAD_info(%r2) # get thread_info of prev | ||
170 | tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? | ||
171 | bz __switch_to_no_mcck-__switch_to_base(%r1) | ||
172 | ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev | ||
173 | l %r4,__THREAD_info(%r3) # get thread_info of next | ||
174 | oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next | ||
175 | __switch_to_no_mcck: | ||
164 | stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task | 176 | stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task |
165 | st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp | 177 | st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp |
166 | l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp | 178 | l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp |
@@ -185,6 +197,7 @@ system_call: | |||
185 | sysc_saveall: | 197 | sysc_saveall: |
186 | SAVE_ALL_BASE __LC_SAVE_AREA | 198 | SAVE_ALL_BASE __LC_SAVE_AREA |
187 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 199 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
200 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
188 | lh %r7,0x8a # get svc number from lowcore | 201 | lh %r7,0x8a # get svc number from lowcore |
189 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 202 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
190 | sysc_vtime: | 203 | sysc_vtime: |
@@ -234,6 +247,8 @@ sysc_work_loop: | |||
234 | # One of the work bits is on. Find out which one. | 247 | # One of the work bits is on. Find out which one. |
235 | # | 248 | # |
236 | sysc_work: | 249 | sysc_work: |
250 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | ||
251 | bo BASED(sysc_mcck_pending) | ||
237 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | 252 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED |
238 | bo BASED(sysc_reschedule) | 253 | bo BASED(sysc_reschedule) |
239 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 254 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
@@ -253,6 +268,14 @@ sysc_reschedule: | |||
253 | br %r1 # call scheduler | 268 | br %r1 # call scheduler |
254 | 269 | ||
255 | # | 270 | # |
271 | # _TIF_MCCK_PENDING is set, call handler | ||
272 | # | ||
273 | sysc_mcck_pending: | ||
274 | l %r1,BASED(.Ls390_handle_mcck) | ||
275 | la %r14,BASED(sysc_work_loop) | ||
276 | br %r1 # TIF bit will be cleared by handler | ||
277 | |||
278 | # | ||
256 | # _TIF_SIGPENDING is set, call do_signal | 279 | # _TIF_SIGPENDING is set, call do_signal |
257 | # | 280 | # |
258 | sysc_sigpending: | 281 | sysc_sigpending: |
@@ -430,6 +453,7 @@ pgm_check_handler: | |||
430 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception | 453 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception |
431 | bnz BASED(pgm_per) # got per exception -> special case | 454 | bnz BASED(pgm_per) # got per exception -> special case |
432 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 | 455 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 |
456 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
433 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 457 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
434 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 458 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
435 | bz BASED(pgm_no_vtime) | 459 | bz BASED(pgm_no_vtime) |
@@ -468,6 +492,7 @@ pgm_per: | |||
468 | # | 492 | # |
469 | pgm_per_std: | 493 | pgm_per_std: |
470 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 | 494 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 |
495 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
471 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 496 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
472 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 497 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
473 | bz BASED(pgm_no_vtime2) | 498 | bz BASED(pgm_no_vtime2) |
@@ -493,6 +518,7 @@ pgm_no_vtime2: | |||
493 | # | 518 | # |
494 | pgm_svcper: | 519 | pgm_svcper: |
495 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 520 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
521 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
496 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 522 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
497 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 523 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
498 | bz BASED(pgm_no_vtime3) | 524 | bz BASED(pgm_no_vtime3) |
@@ -521,6 +547,7 @@ io_int_handler: | |||
521 | stck __LC_INT_CLOCK | 547 | stck __LC_INT_CLOCK |
522 | SAVE_ALL_BASE __LC_SAVE_AREA+16 | 548 | SAVE_ALL_BASE __LC_SAVE_AREA+16 |
523 | SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0 | 549 | SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0 |
550 | CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 | ||
524 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 551 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
525 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 552 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
526 | bz BASED(io_no_vtime) | 553 | bz BASED(io_no_vtime) |
@@ -578,9 +605,11 @@ io_work: | |||
578 | lr %r15,%r1 | 605 | lr %r15,%r1 |
579 | # | 606 | # |
580 | # One of the work bits is on. Find out which one. | 607 | # One of the work bits is on. Find out which one. |
581 | # Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED | 608 | # Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING |
582 | # | 609 | # |
583 | io_work_loop: | 610 | io_work_loop: |
611 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | ||
612 | bo BASED(io_mcck_pending) | ||
584 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | 613 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED |
585 | bo BASED(io_reschedule) | 614 | bo BASED(io_reschedule) |
586 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 615 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
@@ -588,6 +617,14 @@ io_work_loop: | |||
588 | b BASED(io_leave) | 617 | b BASED(io_leave) |
589 | 618 | ||
590 | # | 619 | # |
620 | # _TIF_MCCK_PENDING is set, call handler | ||
621 | # | ||
622 | io_mcck_pending: | ||
623 | l %r1,BASED(.Ls390_handle_mcck) | ||
624 | l %r14,BASED(io_work_loop) | ||
625 | br %r1 # TIF bit will be cleared by handler | ||
626 | |||
627 | # | ||
591 | # _TIF_NEED_RESCHED is set, call schedule | 628 | # _TIF_NEED_RESCHED is set, call schedule |
592 | # | 629 | # |
593 | io_reschedule: | 630 | io_reschedule: |
@@ -621,6 +658,7 @@ ext_int_handler: | |||
621 | stck __LC_INT_CLOCK | 658 | stck __LC_INT_CLOCK |
622 | SAVE_ALL_BASE __LC_SAVE_AREA+16 | 659 | SAVE_ALL_BASE __LC_SAVE_AREA+16 |
623 | SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0 | 660 | SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0 |
661 | CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 | ||
624 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 662 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
625 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 663 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
626 | bz BASED(ext_no_vtime) | 664 | bz BASED(ext_no_vtime) |
@@ -642,19 +680,62 @@ ext_no_vtime: | |||
642 | 680 | ||
643 | .globl mcck_int_handler | 681 | .globl mcck_int_handler |
644 | mcck_int_handler: | 682 | mcck_int_handler: |
645 | STORE_TIMER __LC_ASYNC_ENTER_TIMER | 683 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer |
684 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs | ||
646 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 685 | SAVE_ALL_BASE __LC_SAVE_AREA+32 |
647 | SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0 | 686 | la %r12,__LC_MCK_OLD_PSW |
687 | tm __LC_MCCK_CODE,0x80 # system damage? | ||
688 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid | ||
689 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | ||
690 | bo BASED(0f) | ||
691 | spt __LC_LAST_UPDATE_TIMER # revalidate cpu timer | ||
648 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 692 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
649 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 693 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
694 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
695 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER | ||
696 | 0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | ||
697 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical | ||
698 | tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ? | ||
650 | bz BASED(mcck_no_vtime) | 699 | bz BASED(mcck_no_vtime) |
651 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 700 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
652 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 701 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
653 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 702 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
654 | mcck_no_vtime: | 703 | mcck_no_vtime: |
655 | #endif | 704 | #endif |
705 | 0: | ||
706 | tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | ||
707 | bno BASED(mcck_int_main) # no -> skip cleanup critical | ||
708 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | ||
709 | bnz BASED(mcck_int_main) # from user -> load async stack | ||
710 | clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end) | ||
711 | bhe BASED(mcck_int_main) | ||
712 | clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start) | ||
713 | bl BASED(mcck_int_main) | ||
714 | l %r14,BASED(.Lcleanup_critical) | ||
715 | basr %r14,%r14 | ||
716 | mcck_int_main: | ||
717 | l %r14,__LC_PANIC_STACK # are we already on the panic stack? | ||
718 | slr %r14,%r15 | ||
719 | sra %r14,PAGE_SHIFT | ||
720 | be BASED(0f) | ||
721 | l %r15,__LC_PANIC_STACK # load panic stack | ||
722 | 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32 | ||
723 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | ||
724 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
656 | l %r1,BASED(.Ls390_mcck) | 725 | l %r1,BASED(.Ls390_mcck) |
657 | basr %r14,%r1 # call machine check handler | 726 | basr %r14,%r1 # call machine check handler |
727 | tm SP_PSW+1(%r15),0x01 # returning to user ? | ||
728 | bno BASED(mcck_return) | ||
729 | l %r1,__LC_KERNEL_STACK # switch to kernel stack | ||
730 | s %r1,BASED(.Lc_spsize) | ||
731 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | ||
732 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | ||
733 | lr %r15,%r1 | ||
734 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | ||
735 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | ||
736 | bno BASED(mcck_return) | ||
737 | l %r1,BASED(.Ls390_handle_mcck) | ||
738 | basr %r14,%r1 # call machine check handler | ||
658 | mcck_return: | 739 | mcck_return: |
659 | RESTORE_ALL 0 | 740 | RESTORE_ALL 0 |
660 | 741 | ||
@@ -742,7 +823,7 @@ cleanup_critical: | |||
742 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop) | 823 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop) |
743 | bl BASED(0f) | 824 | bl BASED(0f) |
744 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4) | 825 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4) |
745 | bl BASED(cleanup_sysc_leave) | 826 | bl BASED(cleanup_sysc_return) |
746 | 0: | 827 | 0: |
747 | br %r14 | 828 | br %r14 |
748 | 829 | ||
@@ -760,6 +841,7 @@ cleanup_system_call: | |||
760 | mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16 | 841 | mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16 |
761 | 0: st %r13,__LC_SAVE_AREA+20 | 842 | 0: st %r13,__LC_SAVE_AREA+20 |
762 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 843 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
844 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
763 | st %r15,__LC_SAVE_AREA+28 | 845 | st %r15,__LC_SAVE_AREA+28 |
764 | lh %r7,0x8a | 846 | lh %r7,0x8a |
765 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 847 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn: | |||
834 | * Symbol constants | 916 | * Symbol constants |
835 | */ | 917 | */ |
836 | .Ls390_mcck: .long s390_do_machine_check | 918 | .Ls390_mcck: .long s390_do_machine_check |
919 | .Ls390_handle_mcck: | ||
920 | .long s390_handle_mcck | ||
837 | .Ldo_IRQ: .long do_IRQ | 921 | .Ldo_IRQ: .long do_IRQ |
838 | .Ldo_extint: .long do_extint | 922 | .Ldo_extint: .long do_extint |
839 | .Ldo_signal: .long do_signal | 923 | .Ldo_signal: .long do_signal |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 51527ab8c8f9..57ca75d0ad7f 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -7,6 +7,7 @@ | |||
7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | 7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), |
8 | * Hartmut Penner (hp@de.ibm.com), | 8 | * Hartmut Penner (hp@de.ibm.com), |
9 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 9 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), |
10 | * Heiko Carstens <heiko.carstens@de.ibm.com> | ||
10 | */ | 11 | */ |
11 | 12 | ||
12 | #include <linux/sys.h> | 13 | #include <linux/sys.h> |
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | |||
52 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 53 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
53 | STACK_SIZE = 1 << STACK_SHIFT | 54 | STACK_SIZE = 1 << STACK_SHIFT |
54 | 55 | ||
55 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 56 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \ |
56 | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) | 57 | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) |
57 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) | 58 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) |
58 | 59 | ||
59 | #define BASED(name) name-system_call(%r13) | 60 | #define BASED(name) name-system_call(%r13) |
60 | 61 | ||
@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) | |||
114 | jz stack_overflow | 115 | jz stack_overflow |
115 | 3: | 116 | 3: |
116 | #endif | 117 | #endif |
117 | 2: aghi %r15,-SP_SIZE # make room for registers & psw | 118 | 2: |
119 | .endm | ||
120 | |||
121 | .macro CREATE_STACK_FRAME psworg,savearea | ||
122 | aghi %r15,-SP_SIZE # make room for registers & psw | ||
118 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 123 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
119 | la %r12,\psworg | 124 | la %r12,\psworg |
120 | stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | 125 | stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 |
@@ -152,6 +157,13 @@ __switch_to: | |||
152 | je __switch_to_noper # we got away without bashing TLB's | 157 | je __switch_to_noper # we got away without bashing TLB's |
153 | lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't | 158 | lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't |
154 | __switch_to_noper: | 159 | __switch_to_noper: |
160 | lg %r4,__THREAD_info(%r2) # get thread_info of prev | ||
161 | tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? | ||
162 | jz __switch_to_no_mcck | ||
163 | ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev | ||
164 | lg %r4,__THREAD_info(%r3) # get thread_info of next | ||
165 | oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next | ||
166 | __switch_to_no_mcck: | ||
155 | stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task | 167 | stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task |
156 | stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp | 168 | stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp |
157 | lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp | 169 | lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp |
@@ -176,6 +188,7 @@ system_call: | |||
176 | sysc_saveall: | 188 | sysc_saveall: |
177 | SAVE_ALL_BASE __LC_SAVE_AREA | 189 | SAVE_ALL_BASE __LC_SAVE_AREA |
178 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 190 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
191 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
179 | llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore | 192 | llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore |
180 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 193 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
181 | sysc_vtime: | 194 | sysc_vtime: |
@@ -232,6 +245,8 @@ sysc_work_loop: | |||
232 | # One of the work bits is on. Find out which one. | 245 | # One of the work bits is on. Find out which one. |
233 | # | 246 | # |
234 | sysc_work: | 247 | sysc_work: |
248 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | ||
249 | jo sysc_mcck_pending | ||
235 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED | 250 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED |
236 | jo sysc_reschedule | 251 | jo sysc_reschedule |
237 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 252 | tm __TI_flags+7(%r9),_TIF_SIGPENDING |
@@ -250,6 +265,13 @@ sysc_reschedule: | |||
250 | jg schedule # return point is sysc_return | 265 | jg schedule # return point is sysc_return |
251 | 266 | ||
252 | # | 267 | # |
268 | # _TIF_MCCK_PENDING is set, call handler | ||
269 | # | ||
270 | sysc_mcck_pending: | ||
271 | larl %r14,sysc_work_loop | ||
272 | jg s390_handle_mcck # TIF bit will be cleared by handler | ||
273 | |||
274 | # | ||
253 | # _TIF_SIGPENDING is set, call do_signal | 275 | # _TIF_SIGPENDING is set, call do_signal |
254 | # | 276 | # |
255 | sysc_sigpending: | 277 | sysc_sigpending: |
@@ -474,6 +496,7 @@ pgm_check_handler: | |||
474 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception | 496 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception |
475 | jnz pgm_per # got per exception -> special case | 497 | jnz pgm_per # got per exception -> special case |
476 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 | 498 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 |
499 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
477 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 500 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
478 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 501 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
479 | jz pgm_no_vtime | 502 | jz pgm_no_vtime |
@@ -512,6 +535,7 @@ pgm_per: | |||
512 | # | 535 | # |
513 | pgm_per_std: | 536 | pgm_per_std: |
514 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 | 537 | SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 |
538 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | ||
515 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 539 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
516 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 540 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
517 | jz pgm_no_vtime2 | 541 | jz pgm_no_vtime2 |
@@ -537,6 +561,7 @@ pgm_no_vtime2: | |||
537 | # | 561 | # |
538 | pgm_svcper: | 562 | pgm_svcper: |
539 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 563 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
564 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
540 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 565 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
541 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 566 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
542 | jz pgm_no_vtime3 | 567 | jz pgm_no_vtime3 |
@@ -564,6 +589,7 @@ io_int_handler: | |||
564 | stck __LC_INT_CLOCK | 589 | stck __LC_INT_CLOCK |
565 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 590 | SAVE_ALL_BASE __LC_SAVE_AREA+32 |
566 | SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 | 591 | SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 |
592 | CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 | ||
567 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 593 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
568 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 594 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
569 | jz io_no_vtime | 595 | jz io_no_vtime |
@@ -621,9 +647,11 @@ io_work: | |||
621 | lgr %r15,%r1 | 647 | lgr %r15,%r1 |
622 | # | 648 | # |
623 | # One of the work bits is on. Find out which one. | 649 | # One of the work bits is on. Find out which one. |
624 | # Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED | 650 | # Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING |
625 | # | 651 | # |
626 | io_work_loop: | 652 | io_work_loop: |
653 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | ||
654 | jo io_mcck_pending | ||
627 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED | 655 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED |
628 | jo io_reschedule | 656 | jo io_reschedule |
629 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 657 | tm __TI_flags+7(%r9),_TIF_SIGPENDING |
@@ -631,6 +659,13 @@ io_work_loop: | |||
631 | j io_leave | 659 | j io_leave |
632 | 660 | ||
633 | # | 661 | # |
662 | # _TIF_MCCK_PENDING is set, call handler | ||
663 | # | ||
664 | io_mcck_pending: | ||
665 | larl %r14,io_work_loop | ||
666 | jg s390_handle_mcck # TIF bit will be cleared by handler | ||
667 | |||
668 | # | ||
634 | # _TIF_NEED_RESCHED is set, call schedule | 669 | # _TIF_NEED_RESCHED is set, call schedule |
635 | # | 670 | # |
636 | io_reschedule: | 671 | io_reschedule: |
@@ -661,6 +696,7 @@ ext_int_handler: | |||
661 | stck __LC_INT_CLOCK | 696 | stck __LC_INT_CLOCK |
662 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 697 | SAVE_ALL_BASE __LC_SAVE_AREA+32 |
663 | SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 | 698 | SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 |
699 | CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 | ||
664 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 700 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
665 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 701 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
666 | jz ext_no_vtime | 702 | jz ext_no_vtime |
@@ -680,18 +716,60 @@ ext_no_vtime: | |||
680 | */ | 716 | */ |
681 | .globl mcck_int_handler | 717 | .globl mcck_int_handler |
682 | mcck_int_handler: | 718 | mcck_int_handler: |
683 | STORE_TIMER __LC_ASYNC_ENTER_TIMER | 719 | la %r1,4095 # revalidate r1 |
720 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer | ||
721 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs | ||
684 | SAVE_ALL_BASE __LC_SAVE_AREA+64 | 722 | SAVE_ALL_BASE __LC_SAVE_AREA+64 |
685 | SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0 | 723 | la %r12,__LC_MCK_OLD_PSW |
724 | tm __LC_MCCK_CODE,0x80 # system damage? | ||
725 | jo mcck_int_main # yes -> rest of mcck code invalid | ||
726 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | ||
727 | jo 0f | ||
728 | spt __LC_LAST_UPDATE_TIMER | ||
686 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 729 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
687 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 730 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
731 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | ||
732 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER | ||
733 | 0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | ||
734 | jno mcck_no_vtime # no -> no timer update | ||
735 | tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ? | ||
688 | jz mcck_no_vtime | 736 | jz mcck_no_vtime |
689 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 737 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
690 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 738 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
691 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 739 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
692 | mcck_no_vtime: | 740 | mcck_no_vtime: |
693 | #endif | 741 | #endif |
694 | brasl %r14,s390_do_machine_check | 742 | 0: |
743 | tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | ||
744 | jno mcck_int_main # no -> skip cleanup critical | ||
745 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | ||
746 | jnz mcck_int_main # from user -> load kernel stack | ||
747 | clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end) | ||
748 | jhe mcck_int_main | ||
749 | clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) | ||
750 | jl mcck_int_main | ||
751 | brasl %r14,cleanup_critical | ||
752 | mcck_int_main: | ||
753 | lg %r14,__LC_PANIC_STACK # are we already on the panic stack? | ||
754 | slgr %r14,%r15 | ||
755 | srag %r14,%r14,PAGE_SHIFT | ||
756 | jz 0f | ||
757 | lg %r15,__LC_PANIC_STACK # load panic stack | ||
758 | 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 | ||
759 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | ||
760 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
761 | brasl %r14,s390_do_machine_check | ||
762 | tm SP_PSW+1(%r15),0x01 # returning to user ? | ||
763 | jno mcck_return | ||
764 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack | ||
765 | aghi %r1,-SP_SIZE | ||
766 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | ||
767 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | ||
768 | lgr %r15,%r1 | ||
769 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | ||
770 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | ||
771 | jno mcck_return | ||
772 | brasl %r14,s390_handle_mcck | ||
695 | mcck_return: | 773 | mcck_return: |
696 | RESTORE_ALL 0 | 774 | RESTORE_ALL 0 |
697 | 775 | ||
@@ -775,7 +853,7 @@ cleanup_critical: | |||
775 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) | 853 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) |
776 | jl 0f | 854 | jl 0f |
777 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) | 855 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) |
778 | jl cleanup_sysc_leave | 856 | jl cleanup_sysc_return |
779 | 0: | 857 | 0: |
780 | br %r14 | 858 | br %r14 |
781 | 859 | ||
@@ -793,6 +871,7 @@ cleanup_system_call: | |||
793 | mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 | 871 | mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 |
794 | 0: stg %r13,__LC_SAVE_AREA+40 | 872 | 0: stg %r13,__LC_SAVE_AREA+40 |
795 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 | 873 | SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 |
874 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | ||
796 | stg %r15,__LC_SAVE_AREA+56 | 875 | stg %r15,__LC_SAVE_AREA+56 |
797 | llgh %r7,__LC_SVC_INT_CODE | 876 | llgh %r7,__LC_SVC_INT_CODE |
798 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 877 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7aea25d6e300..9f3dff6c0b72 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) | |||
91 | (void *)(long) smp_processor_id()); | 91 | (void *)(long) smp_processor_id()); |
92 | } | 92 | } |
93 | 93 | ||
94 | extern void s390_handle_mcck(void); | ||
94 | /* | 95 | /* |
95 | * The idle loop on a S390... | 96 | * The idle loop on a S390... |
96 | */ | 97 | */ |
97 | void default_idle(void) | 98 | void default_idle(void) |
98 | { | 99 | { |
99 | psw_t wait_psw; | ||
100 | unsigned long reg; | ||
101 | int cpu, rc; | 100 | int cpu, rc; |
102 | 101 | ||
103 | local_irq_disable(); | 102 | local_irq_disable(); |
@@ -125,38 +124,17 @@ void default_idle(void) | |||
125 | cpu_die(); | 124 | cpu_die(); |
126 | #endif | 125 | #endif |
127 | 126 | ||
128 | /* | 127 | local_mcck_disable(); |
129 | * Wait for external, I/O or machine check interrupt and | 128 | if (test_thread_flag(TIF_MCCK_PENDING)) { |
130 | * switch off machine check bit after the wait has ended. | 129 | local_mcck_enable(); |
131 | */ | 130 | local_irq_enable(); |
132 | wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT | | 131 | s390_handle_mcck(); |
133 | PSW_MASK_IO | PSW_MASK_EXT; | 132 | return; |
134 | #ifndef CONFIG_ARCH_S390X | 133 | } |
135 | asm volatile ( | 134 | |
136 | " basr %0,0\n" | 135 | /* Wait for external, I/O or machine check interrupt. */ |
137 | "0: la %0,1f-0b(%0)\n" | 136 | __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | |
138 | " st %0,4(%1)\n" | 137 | PSW_MASK_IO | PSW_MASK_EXT); |
139 | " oi 4(%1),0x80\n" | ||
140 | " lpsw 0(%1)\n" | ||
141 | "1: la %0,2f-1b(%0)\n" | ||
142 | " st %0,4(%1)\n" | ||
143 | " oi 4(%1),0x80\n" | ||
144 | " ni 1(%1),0xf9\n" | ||
145 | " lpsw 0(%1)\n" | ||
146 | "2:" | ||
147 | : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); | ||
148 | #else /* CONFIG_ARCH_S390X */ | ||
149 | asm volatile ( | ||
150 | " larl %0,0f\n" | ||
151 | " stg %0,8(%1)\n" | ||
152 | " lpswe 0(%1)\n" | ||
153 | "0: larl %0,1f\n" | ||
154 | " stg %0,8(%1)\n" | ||
155 | " ni 1(%1),0xf9\n" | ||
156 | " lpswe 0(%1)\n" | ||
157 | "1:" | ||
158 | : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); | ||
159 | #endif /* CONFIG_ARCH_S390X */ | ||
160 | } | 138 | } |
161 | 139 | ||
162 | void cpu_idle(void) | 140 | void cpu_idle(void) |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index df83215beac3..eb7be0ad7175 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -414,7 +414,8 @@ setup_lowcore(void) | |||
414 | lc->program_new_psw.mask = PSW_KERNEL_BITS; | 414 | lc->program_new_psw.mask = PSW_KERNEL_BITS; |
415 | lc->program_new_psw.addr = | 415 | lc->program_new_psw.addr = |
416 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; | 416 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; |
417 | lc->mcck_new_psw.mask = PSW_KERNEL_BITS; | 417 | lc->mcck_new_psw.mask = |
418 | PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; | ||
418 | lc->mcck_new_psw.addr = | 419 | lc->mcck_new_psw.addr = |
419 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; | 420 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; |
420 | lc->io_new_psw.mask = PSW_KERNEL_BITS; | 421 | lc->io_new_psw.mask = PSW_KERNEL_BITS; |
@@ -424,12 +425,18 @@ setup_lowcore(void) | |||
424 | lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; | 425 | lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; |
425 | lc->async_stack = (unsigned long) | 426 | lc->async_stack = (unsigned long) |
426 | __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; | 427 | __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; |
427 | #ifdef CONFIG_CHECK_STACK | ||
428 | lc->panic_stack = (unsigned long) | 428 | lc->panic_stack = (unsigned long) |
429 | __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; | 429 | __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; |
430 | #endif | ||
431 | lc->current_task = (unsigned long) init_thread_union.thread_info.task; | 430 | lc->current_task = (unsigned long) init_thread_union.thread_info.task; |
432 | lc->thread_info = (unsigned long) &init_thread_union; | 431 | lc->thread_info = (unsigned long) &init_thread_union; |
432 | #ifndef CONFIG_ARCH_S390X | ||
433 | if (MACHINE_HAS_IEEE) { | ||
434 | lc->extended_save_area_addr = (__u32) | ||
435 | __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); | ||
436 | /* enable extended save area */ | ||
437 | ctl_set_bit(14, 29); | ||
438 | } | ||
439 | #endif | ||
433 | #ifdef CONFIG_ARCH_S390X | 440 | #ifdef CONFIG_ARCH_S390X |
434 | if (MACHINE_HAS_DIAG44) | 441 | if (MACHINE_HAS_DIAG44) |
435 | lc->diag44_opcode = 0x83000044; | 442 | lc->diag44_opcode = 0x83000044; |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 93c71fef99dc..50c335067cfe 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -773,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
773 | 773 | ||
774 | *(lowcore_ptr[i]) = S390_lowcore; | 774 | *(lowcore_ptr[i]) = S390_lowcore; |
775 | lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); | 775 | lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); |
776 | #ifdef CONFIG_CHECK_STACK | ||
777 | stack = __get_free_pages(GFP_KERNEL,0); | 776 | stack = __get_free_pages(GFP_KERNEL,0); |
778 | if (stack == 0ULL) | 777 | if (stack == 0ULL) |
779 | panic("smp_boot_cpus failed to allocate memory\n"); | 778 | panic("smp_boot_cpus failed to allocate memory\n"); |
780 | lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); | 779 | lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); |
780 | #ifndef __s390x__ | ||
781 | if (MACHINE_HAS_IEEE) { | ||
782 | lowcore_ptr[i]->extended_save_area_addr = | ||
783 | (__u32) __get_free_pages(GFP_KERNEL,0); | ||
784 | if (lowcore_ptr[i]->extended_save_area_addr == 0) | ||
785 | panic("smp_boot_cpus failed to " | ||
786 | "allocate memory\n"); | ||
787 | } | ||
781 | #endif | 788 | #endif |
782 | } | 789 | } |
790 | #ifndef __s390x__ | ||
791 | if (MACHINE_HAS_IEEE) | ||
792 | ctl_set_bit(14, 29); /* enable extended save area */ | ||
793 | #endif | ||
783 | set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); | 794 | set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); |
784 | 795 | ||
785 | for_each_cpu(cpu) | 796 | for_each_cpu(cpu) |
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index ffa996c8a908..5bb255e02acc 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
@@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void); | |||
31 | extern struct workqueue_struct *slow_path_wq; | 31 | extern struct workqueue_struct *slow_path_wq; |
32 | extern struct work_struct slow_path_work; | 32 | extern struct work_struct slow_path_work; |
33 | 33 | ||
34 | static void | 34 | static NORET_TYPE void |
35 | s390_handle_damage(char *msg) | 35 | s390_handle_damage(char *msg) |
36 | { | 36 | { |
37 | printk(KERN_EMERG "%s\n", msg); | ||
38 | #ifdef CONFIG_SMP | 37 | #ifdef CONFIG_SMP |
39 | smp_send_stop(); | 38 | smp_send_stop(); |
40 | #endif | 39 | #endif |
41 | disabled_wait((unsigned long) __builtin_return_address(0)); | 40 | disabled_wait((unsigned long) __builtin_return_address(0)); |
41 | for(;;); | ||
42 | } | 42 | } |
43 | 43 | ||
44 | /* | 44 | /* |
@@ -122,40 +122,39 @@ repeat: | |||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | struct mcck_struct { | ||
126 | int kill_task; | ||
127 | int channel_report; | ||
128 | int warning; | ||
129 | unsigned long long mcck_code; | ||
130 | }; | ||
131 | |||
132 | static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); | ||
133 | |||
125 | /* | 134 | /* |
126 | * machine check handler. | 135 | * Main machine check handler function. Will be called with interrupts enabled |
136 | * or disabled and machine checks enabled or disabled. | ||
127 | */ | 137 | */ |
128 | void | 138 | void |
129 | s390_do_machine_check(void) | 139 | s390_handle_mcck(void) |
130 | { | 140 | { |
131 | struct mci *mci; | 141 | unsigned long flags; |
132 | 142 | struct mcck_struct mcck; | |
133 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; | ||
134 | 143 | ||
135 | if (mci->sd) /* system damage */ | 144 | /* |
136 | s390_handle_damage("received system damage machine check\n"); | 145 | * Disable machine checks and get the current state of accumulated |
146 | * machine checks. Afterwards delete the old state and enable machine | ||
147 | * checks again. | ||
148 | */ | ||
149 | local_irq_save(flags); | ||
150 | local_mcck_disable(); | ||
151 | mcck = __get_cpu_var(cpu_mcck); | ||
152 | memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); | ||
153 | clear_thread_flag(TIF_MCCK_PENDING); | ||
154 | local_mcck_enable(); | ||
155 | local_irq_restore(flags); | ||
137 | 156 | ||
138 | if (mci->pd) /* instruction processing damage */ | 157 | if (mcck.channel_report) |
139 | s390_handle_damage("received instruction processing " | ||
140 | "damage machine check\n"); | ||
141 | |||
142 | if (mci->se) /* storage error uncorrected */ | ||
143 | s390_handle_damage("received storage error uncorrected " | ||
144 | "machine check\n"); | ||
145 | |||
146 | if (mci->sc) /* storage error corrected */ | ||
147 | printk(KERN_WARNING | ||
148 | "received storage error corrected machine check\n"); | ||
149 | |||
150 | if (mci->ke) /* storage key-error uncorrected */ | ||
151 | s390_handle_damage("received storage key-error uncorrected " | ||
152 | "machine check\n"); | ||
153 | |||
154 | if (mci->ds && mci->fa) /* storage degradation */ | ||
155 | s390_handle_damage("received storage degradation machine " | ||
156 | "check\n"); | ||
157 | |||
158 | if (mci->cp) /* channel report word pending */ | ||
159 | up(&m_sem); | 158 | up(&m_sem); |
160 | 159 | ||
161 | #ifdef CONFIG_MACHCHK_WARNING | 160 | #ifdef CONFIG_MACHCHK_WARNING |
@@ -168,7 +167,7 @@ s390_do_machine_check(void) | |||
168 | * On VM we only get one interrupt per virtally presented machinecheck. | 167 | * On VM we only get one interrupt per virtally presented machinecheck. |
169 | * Though one suffices, we may get one interrupt per (virtual) processor. | 168 | * Though one suffices, we may get one interrupt per (virtual) processor. |
170 | */ | 169 | */ |
171 | if (mci->w) { /* WARNING pending ? */ | 170 | if (mcck.warning) { /* WARNING pending ? */ |
172 | static int mchchk_wng_posted = 0; | 171 | static int mchchk_wng_posted = 0; |
173 | /* | 172 | /* |
174 | * Use single machine clear, as we cannot handle smp right now | 173 | * Use single machine clear, as we cannot handle smp right now |
@@ -178,6 +177,261 @@ s390_do_machine_check(void) | |||
178 | kill_proc(1, SIGPWR, 1); | 177 | kill_proc(1, SIGPWR, 1); |
179 | } | 178 | } |
180 | #endif | 179 | #endif |
180 | |||
181 | if (mcck.kill_task) { | ||
182 | local_irq_enable(); | ||
183 | printk(KERN_EMERG "mcck: Terminating task because of machine " | ||
184 | "malfunction (code 0x%016llx).\n", mcck.mcck_code); | ||
185 | printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", | ||
186 | current->comm, current->pid); | ||
187 | do_exit(SIGSEGV); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * returns 0 if all registers could be validated | ||
193 | * returns 1 otherwise | ||
194 | */ | ||
195 | static int | ||
196 | s390_revalidate_registers(struct mci *mci) | ||
197 | { | ||
198 | int kill_task; | ||
199 | u64 tmpclock; | ||
200 | u64 zero; | ||
201 | void *fpt_save_area, *fpt_creg_save_area; | ||
202 | |||
203 | kill_task = 0; | ||
204 | zero = 0; | ||
205 | /* General purpose registers */ | ||
206 | if (!mci->gr) | ||
207 | /* | ||
208 | * General purpose registers couldn't be restored and have | ||
209 | * unknown contents. Process needs to be terminated. | ||
210 | */ | ||
211 | kill_task = 1; | ||
212 | |||
213 | /* Revalidate floating point registers */ | ||
214 | if (!mci->fp) | ||
215 | /* | ||
216 | * Floating point registers can't be restored and | ||
217 | * therefore the process needs to be terminated. | ||
218 | */ | ||
219 | kill_task = 1; | ||
220 | |||
221 | #ifndef __s390x__ | ||
222 | asm volatile("ld 0,0(%0)\n" | ||
223 | "ld 2,8(%0)\n" | ||
224 | "ld 4,16(%0)\n" | ||
225 | "ld 6,24(%0)" | ||
226 | : : "a" (&S390_lowcore.floating_pt_save_area)); | ||
227 | #endif | ||
228 | |||
229 | if (MACHINE_HAS_IEEE) { | ||
230 | #ifdef __s390x__ | ||
231 | fpt_save_area = &S390_lowcore.floating_pt_save_area; | ||
232 | fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; | ||
233 | #else | ||
234 | fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; | ||
235 | fpt_creg_save_area = fpt_save_area+128; | ||
236 | #endif | ||
237 | /* Floating point control register */ | ||
238 | if (!mci->fc) { | ||
239 | /* | ||
240 | * Floating point control register can't be restored. | ||
241 | * Task will be terminated. | ||
242 | */ | ||
243 | asm volatile ("lfpc 0(%0)" : : "a" (&zero)); | ||
244 | kill_task = 1; | ||
245 | |||
246 | } | ||
247 | else | ||
248 | asm volatile ( | ||
249 | "lfpc 0(%0)" | ||
250 | : : "a" (fpt_creg_save_area)); | ||
251 | |||
252 | asm volatile("ld 0,0(%0)\n" | ||
253 | "ld 1,8(%0)\n" | ||
254 | "ld 2,16(%0)\n" | ||
255 | "ld 3,24(%0)\n" | ||
256 | "ld 4,32(%0)\n" | ||
257 | "ld 5,40(%0)\n" | ||
258 | "ld 6,48(%0)\n" | ||
259 | "ld 7,56(%0)\n" | ||
260 | "ld 8,64(%0)\n" | ||
261 | "ld 9,72(%0)\n" | ||
262 | "ld 10,80(%0)\n" | ||
263 | "ld 11,88(%0)\n" | ||
264 | "ld 12,96(%0)\n" | ||
265 | "ld 13,104(%0)\n" | ||
266 | "ld 14,112(%0)\n" | ||
267 | "ld 15,120(%0)\n" | ||
268 | : : "a" (fpt_save_area)); | ||
269 | } | ||
270 | |||
271 | /* Revalidate access registers */ | ||
272 | asm volatile("lam 0,15,0(%0)" | ||
273 | : : "a" (&S390_lowcore.access_regs_save_area)); | ||
274 | if (!mci->ar) | ||
275 | /* | ||
276 | * Access registers have unknown contents. | ||
277 | * Terminating task. | ||
278 | */ | ||
279 | kill_task = 1; | ||
280 | |||
281 | /* Revalidate control registers */ | ||
282 | if (!mci->cr) | ||
283 | /* | ||
284 | * Control registers have unknown contents. | ||
285 | * Can't recover and therefore stopping machine. | ||
286 | */ | ||
287 | s390_handle_damage("invalid control registers."); | ||
288 | else | ||
289 | #ifdef __s390x__ | ||
290 | asm volatile("lctlg 0,15,0(%0)" | ||
291 | : : "a" (&S390_lowcore.cregs_save_area)); | ||
292 | #else | ||
293 | asm volatile("lctl 0,15,0(%0)" | ||
294 | : : "a" (&S390_lowcore.cregs_save_area)); | ||
295 | #endif | ||
296 | |||
297 | /* | ||
298 | * We don't even try to revalidate the TOD register, since we simply | ||
299 | * can't write something sensible into that register. | ||
300 | */ | ||
301 | |||
302 | #ifdef __s390x__ | ||
303 | /* | ||
304 | * See if we can revalidate the TOD programmable register with its | ||
305 | * old contents (should be zero) otherwise set it to zero. | ||
306 | */ | ||
307 | if (!mci->pr) | ||
308 | asm volatile("sr 0,0\n" | ||
309 | "sckpf" | ||
310 | : : : "0", "cc"); | ||
311 | else | ||
312 | asm volatile( | ||
313 | "l 0,0(%0)\n" | ||
314 | "sckpf" | ||
315 | : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc"); | ||
316 | #endif | ||
317 | |||
318 | /* Revalidate clock comparator register */ | ||
319 | asm volatile ("stck 0(%1)\n" | ||
320 | "sckc 0(%1)" | ||
321 | : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); | ||
322 | |||
323 | /* Check if old PSW is valid */ | ||
324 | if (!mci->wp) | ||
325 | /* | ||
326 | * Can't tell if we come from user or kernel mode | ||
327 | * -> stopping machine. | ||
328 | */ | ||
329 | s390_handle_damage("old psw invalid."); | ||
330 | |||
331 | if (!mci->ms || !mci->pm || !mci->ia) | ||
332 | kill_task = 1; | ||
333 | |||
334 | return kill_task; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * machine check handler. | ||
339 | */ | ||
340 | void | ||
341 | s390_do_machine_check(struct pt_regs *regs) | ||
342 | { | ||
343 | struct mci *mci; | ||
344 | struct mcck_struct *mcck; | ||
345 | int umode; | ||
346 | |||
347 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; | ||
348 | mcck = &__get_cpu_var(cpu_mcck); | ||
349 | umode = user_mode(regs); | ||
350 | |||
351 | if (mci->sd) | ||
352 | /* System damage -> stopping machine */ | ||
353 | s390_handle_damage("received system damage machine check."); | ||
354 | |||
355 | if (mci->pd) { | ||
356 | if (mci->b) { | ||
357 | /* Processing backup -> verify if we can survive this */ | ||
358 | u64 z_mcic, o_mcic, t_mcic; | ||
359 | #ifdef __s390x__ | ||
360 | z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); | ||
361 | o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | | ||
362 | 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | | ||
363 | 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | | ||
364 | 1ULL<<16); | ||
365 | #else | ||
366 | z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 | | ||
367 | 1ULL<<29); | ||
368 | o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | | ||
369 | 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | | ||
370 | 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16); | ||
371 | #endif | ||
372 | t_mcic = *(u64 *)mci; | ||
373 | |||
374 | if (((t_mcic & z_mcic) != 0) || | ||
375 | ((t_mcic & o_mcic) != o_mcic)) { | ||
376 | s390_handle_damage("processing backup machine " | ||
377 | "check with damage."); | ||
378 | } | ||
379 | if (!umode) | ||
380 | s390_handle_damage("processing backup machine " | ||
381 | "check in kernel mode."); | ||
382 | mcck->kill_task = 1; | ||
383 | mcck->mcck_code = *(unsigned long long *) mci; | ||
384 | } | ||
385 | else { | ||
386 | /* Processing damage -> stopping machine */ | ||
387 | s390_handle_damage("received instruction processing " | ||
388 | "damage machine check."); | ||
389 | } | ||
390 | } | ||
391 | if (s390_revalidate_registers(mci)) { | ||
392 | if (umode) { | ||
393 | /* | ||
394 | * Couldn't restore all register contents while in | ||
395 | * user mode -> mark task for termination. | ||
396 | */ | ||
397 | mcck->kill_task = 1; | ||
398 | mcck->mcck_code = *(unsigned long long *) mci; | ||
399 | set_thread_flag(TIF_MCCK_PENDING); | ||
400 | } | ||
401 | else | ||
402 | /* | ||
403 | * Couldn't restore all register contents while in | ||
404 | * kernel mode -> stopping machine. | ||
405 | */ | ||
406 | s390_handle_damage("unable to revalidate registers."); | ||
407 | } | ||
408 | |||
409 | if (mci->se) | ||
410 | /* Storage error uncorrected */ | ||
411 | s390_handle_damage("received storage error uncorrected " | ||
412 | "machine check."); | ||
413 | |||
414 | if (mci->ke) | ||
415 | /* Storage key-error uncorrected */ | ||
416 | s390_handle_damage("received storage key-error uncorrected " | ||
417 | "machine check."); | ||
418 | |||
419 | if (mci->ds && mci->fa) | ||
420 | /* Storage degradation */ | ||
421 | s390_handle_damage("received storage degradation machine " | ||
422 | "check."); | ||
423 | |||
424 | if (mci->cp) { | ||
425 | /* Channel report word pending */ | ||
426 | mcck->channel_report = 1; | ||
427 | set_thread_flag(TIF_MCCK_PENDING); | ||
428 | } | ||
429 | |||
430 | if (mci->w) { | ||
431 | /* Warning pending */ | ||
432 | mcck->warning = 1; | ||
433 | set_thread_flag(TIF_MCCK_PENDING); | ||
434 | } | ||
181 | } | 435 | } |
182 | 436 | ||
183 | /* | 437 | /* |
@@ -189,9 +443,8 @@ static int | |||
189 | machine_check_init(void) | 443 | machine_check_init(void) |
190 | { | 444 | { |
191 | init_MUTEX_LOCKED(&m_sem); | 445 | init_MUTEX_LOCKED(&m_sem); |
192 | ctl_clear_bit(14, 25); /* disable damage MCH */ | 446 | ctl_clear_bit(14, 25); /* disable external damage MCH */ |
193 | ctl_set_bit(14, 26); /* enable degradation MCH */ | 447 | ctl_set_bit(14, 27); /* enable system recovery MCH */ |
194 | ctl_set_bit(14, 27); /* enable system recovery MCH */ | ||
195 | #ifdef CONFIG_MACHCHK_WARNING | 448 | #ifdef CONFIG_MACHCHK_WARNING |
196 | ctl_set_bit(14, 24); /* enable warning MCH */ | 449 | ctl_set_bit(14, 24); /* enable warning MCH */ |
197 | #endif | 450 | #endif |
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7e26f0f1b0dc..4eaa70179182 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h | |||
@@ -16,20 +16,45 @@ struct mci { | |||
16 | __u32 sd : 1; /* 00 system damage */ | 16 | __u32 sd : 1; /* 00 system damage */ |
17 | __u32 pd : 1; /* 01 instruction-processing damage */ | 17 | __u32 pd : 1; /* 01 instruction-processing damage */ |
18 | __u32 sr : 1; /* 02 system recovery */ | 18 | __u32 sr : 1; /* 02 system recovery */ |
19 | __u32 to_be_defined_1 : 4; /* 03-06 */ | 19 | __u32 to_be_defined_1 : 1; /* 03 */ |
20 | __u32 cd : 1; /* 04 timing-facility damage */ | ||
21 | __u32 ed : 1; /* 05 external damage */ | ||
22 | __u32 to_be_defined_2 : 1; /* 06 */ | ||
20 | __u32 dg : 1; /* 07 degradation */ | 23 | __u32 dg : 1; /* 07 degradation */ |
21 | __u32 w : 1; /* 08 warning pending */ | 24 | __u32 w : 1; /* 08 warning pending */ |
22 | __u32 cp : 1; /* 09 channel-report pending */ | 25 | __u32 cp : 1; /* 09 channel-report pending */ |
23 | __u32 to_be_defined_2 : 6; /* 10-15 */ | 26 | __u32 sp : 1; /* 10 service-processor damage */ |
27 | __u32 ck : 1; /* 11 channel-subsystem damage */ | ||
28 | __u32 to_be_defined_3 : 2; /* 12-13 */ | ||
29 | __u32 b : 1; /* 14 backed up */ | ||
30 | __u32 to_be_defined_4 : 1; /* 15 */ | ||
24 | __u32 se : 1; /* 16 storage error uncorrected */ | 31 | __u32 se : 1; /* 16 storage error uncorrected */ |
25 | __u32 sc : 1; /* 17 storage error corrected */ | 32 | __u32 sc : 1; /* 17 storage error corrected */ |
26 | __u32 ke : 1; /* 18 storage-key error uncorrected */ | 33 | __u32 ke : 1; /* 18 storage-key error uncorrected */ |
27 | __u32 ds : 1; /* 19 storage degradation */ | 34 | __u32 ds : 1; /* 19 storage degradation */ |
28 | __u32 to_be_defined_3 : 4; /* 20-23 */ | 35 | __u32 wp : 1; /* 20 psw mwp validity */ |
36 | __u32 ms : 1; /* 21 psw mask and key validity */ | ||
37 | __u32 pm : 1; /* 22 psw program mask and cc validity */ | ||
38 | __u32 ia : 1; /* 23 psw instruction address validity */ | ||
29 | __u32 fa : 1; /* 24 failing storage address validity */ | 39 | __u32 fa : 1; /* 24 failing storage address validity */ |
30 | __u32 to_be_defined_4 : 7; /* 25-31 */ | 40 | __u32 to_be_defined_5 : 1; /* 25 */ |
41 | __u32 ec : 1; /* 26 external damage code validity */ | ||
42 | __u32 fp : 1; /* 27 floating point register validity */ | ||
43 | __u32 gr : 1; /* 28 general register validity */ | ||
44 | __u32 cr : 1; /* 29 control register validity */ | ||
45 | __u32 to_be_defined_6 : 1; /* 30 */ | ||
46 | __u32 st : 1; /* 31 storage logical validity */ | ||
31 | __u32 ie : 1; /* 32 indirect storage error */ | 47 | __u32 ie : 1; /* 32 indirect storage error */ |
32 | __u32 to_be_defined_5 : 31; /* 33-63 */ | 48 | __u32 ar : 1; /* 33 access register validity */ |
49 | __u32 da : 1; /* 34 delayed access exception */ | ||
50 | __u32 to_be_defined_7 : 7; /* 35-41 */ | ||
51 | __u32 pr : 1; /* 42 tod programmable register validity */ | ||
52 | __u32 fc : 1; /* 43 fp control register validity */ | ||
53 | __u32 ap : 1; /* 44 ancillary report */ | ||
54 | __u32 to_be_defined_8 : 1; /* 45 */ | ||
55 | __u32 ct : 1; /* 46 cpu timer validity */ | ||
56 | __u32 cc : 1; /* 47 clock comparator validity */ | ||
57 | __u32 to_be_defined_9 : 16; /* 47-63 */ | ||
33 | }; | 58 | }; |
34 | 59 | ||
35 | /* | 60 | /* |
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index df5172fc589d..76b5b19c0ae2 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h | |||
@@ -109,10 +109,14 @@ | |||
109 | 109 | ||
110 | #ifndef __s390x__ | 110 | #ifndef __s390x__ |
111 | #define __LC_PFAULT_INTPARM 0x080 | 111 | #define __LC_PFAULT_INTPARM 0x080 |
112 | #define __LC_CPU_TIMER_SAVE_AREA 0x0D8 | ||
112 | #define __LC_AREGS_SAVE_AREA 0x120 | 113 | #define __LC_AREGS_SAVE_AREA 0x120 |
114 | #define __LC_GPREGS_SAVE_AREA 0x180 | ||
113 | #define __LC_CREGS_SAVE_AREA 0x1C0 | 115 | #define __LC_CREGS_SAVE_AREA 0x1C0 |
114 | #else /* __s390x__ */ | 116 | #else /* __s390x__ */ |
115 | #define __LC_PFAULT_INTPARM 0x11B8 | 117 | #define __LC_PFAULT_INTPARM 0x11B8 |
118 | #define __LC_GPREGS_SAVE_AREA 0x1280 | ||
119 | #define __LC_CPU_TIMER_SAVE_AREA 0x1328 | ||
116 | #define __LC_AREGS_SAVE_AREA 0x1340 | 120 | #define __LC_AREGS_SAVE_AREA 0x1340 |
117 | #define __LC_CREGS_SAVE_AREA 0x1380 | 121 | #define __LC_CREGS_SAVE_AREA 0x1380 |
118 | #endif /* __s390x__ */ | 122 | #endif /* __s390x__ */ |
@@ -167,7 +171,8 @@ struct _lowcore | |||
167 | __u16 subchannel_nr; /* 0x0ba */ | 171 | __u16 subchannel_nr; /* 0x0ba */ |
168 | __u32 io_int_parm; /* 0x0bc */ | 172 | __u32 io_int_parm; /* 0x0bc */ |
169 | __u32 io_int_word; /* 0x0c0 */ | 173 | __u32 io_int_word; /* 0x0c0 */ |
170 | __u8 pad3[0xD8-0xC4]; /* 0x0c4 */ | 174 | __u8 pad3[0xD4-0xC4]; /* 0x0c4 */ |
175 | __u32 extended_save_area_addr; /* 0x0d4 */ | ||
171 | __u32 cpu_timer_save_area[2]; /* 0x0d8 */ | 176 | __u32 cpu_timer_save_area[2]; /* 0x0d8 */ |
172 | __u32 clock_comp_save_area[2]; /* 0x0e0 */ | 177 | __u32 clock_comp_save_area[2]; /* 0x0e0 */ |
173 | __u32 mcck_interruption_code[2]; /* 0x0e8 */ | 178 | __u32 mcck_interruption_code[2]; /* 0x0e8 */ |
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index fb46e9090b50..8bd14de69e35 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h | |||
@@ -207,6 +207,18 @@ unsigned long get_wchan(struct task_struct *p); | |||
207 | #endif /* __s390x__ */ | 207 | #endif /* __s390x__ */ |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * Set PSW to specified value. | ||
211 | */ | ||
212 | static inline void __load_psw(psw_t psw) | ||
213 | { | ||
214 | #ifndef __s390x__ | ||
215 | asm volatile ("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); | ||
216 | #else | ||
217 | asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); | ||
218 | #endif | ||
219 | } | ||
220 | |||
221 | /* | ||
210 | * Set PSW mask to specified value, while leaving the | 222 | * Set PSW mask to specified value, while leaving the |
211 | * PSW addr pointing to the next instruction. | 223 | * PSW addr pointing to the next instruction. |
212 | */ | 224 | */ |
@@ -214,8 +226,8 @@ unsigned long get_wchan(struct task_struct *p); | |||
214 | static inline void __load_psw_mask (unsigned long mask) | 226 | static inline void __load_psw_mask (unsigned long mask) |
215 | { | 227 | { |
216 | unsigned long addr; | 228 | unsigned long addr; |
217 | |||
218 | psw_t psw; | 229 | psw_t psw; |
230 | |||
219 | psw.mask = mask; | 231 | psw.mask = mask; |
220 | 232 | ||
221 | #ifndef __s390x__ | 233 | #ifndef __s390x__ |
@@ -241,30 +253,8 @@ static inline void __load_psw_mask (unsigned long mask) | |||
241 | */ | 253 | */ |
242 | static inline void enabled_wait(void) | 254 | static inline void enabled_wait(void) |
243 | { | 255 | { |
244 | unsigned long reg; | 256 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT | |
245 | psw_t wait_psw; | 257 | PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY); |
246 | |||
247 | wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT | | ||
248 | PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY; | ||
249 | #ifndef __s390x__ | ||
250 | asm volatile ( | ||
251 | " basr %0,0\n" | ||
252 | "0: la %0,1f-0b(%0)\n" | ||
253 | " st %0,4(%1)\n" | ||
254 | " oi 4(%1),0x80\n" | ||
255 | " lpsw 0(%1)\n" | ||
256 | "1:" | ||
257 | : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw) | ||
258 | : "memory", "cc" ); | ||
259 | #else /* __s390x__ */ | ||
260 | asm volatile ( | ||
261 | " larl %0,0f\n" | ||
262 | " stg %0,8(%1)\n" | ||
263 | " lpswe 0(%1)\n" | ||
264 | "0:" | ||
265 | : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw) | ||
266 | : "memory", "cc" ); | ||
267 | #endif /* __s390x__ */ | ||
268 | } | 258 | } |
269 | 259 | ||
270 | /* | 260 | /* |
@@ -273,13 +263,11 @@ static inline void enabled_wait(void) | |||
273 | 263 | ||
274 | static inline void disabled_wait(unsigned long code) | 264 | static inline void disabled_wait(unsigned long code) |
275 | { | 265 | { |
276 | char psw_buffer[2*sizeof(psw_t)]; | ||
277 | unsigned long ctl_buf; | 266 | unsigned long ctl_buf; |
278 | psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1) | 267 | psw_t dw_psw; |
279 | & -sizeof(psw_t)); | ||
280 | 268 | ||
281 | dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT; | 269 | dw_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; |
282 | dw_psw->addr = code; | 270 | dw_psw.addr = code; |
283 | /* | 271 | /* |
284 | * Store status and then load disabled wait psw, | 272 | * Store status and then load disabled wait psw, |
285 | * the processor is dead afterwards | 273 | * the processor is dead afterwards |
@@ -301,7 +289,7 @@ static inline void disabled_wait(unsigned long code) | |||
301 | " oi 0x1c0,0x10\n" /* fake protection bit */ | 289 | " oi 0x1c0,0x10\n" /* fake protection bit */ |
302 | " lpsw 0(%1)" | 290 | " lpsw 0(%1)" |
303 | : "=m" (ctl_buf) | 291 | : "=m" (ctl_buf) |
304 | : "a" (dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" ); | 292 | : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" ); |
305 | #else /* __s390x__ */ | 293 | #else /* __s390x__ */ |
306 | asm volatile (" stctg 0,0,0(%2)\n" | 294 | asm volatile (" stctg 0,0,0(%2)\n" |
307 | " ni 4(%2),0xef\n" /* switch off protection */ | 295 | " ni 4(%2),0xef\n" /* switch off protection */ |
@@ -333,7 +321,7 @@ static inline void disabled_wait(unsigned long code) | |||
333 | " oi 0x384(1),0x10\n" /* fake protection bit */ | 321 | " oi 0x384(1),0x10\n" /* fake protection bit */ |
334 | " lpswe 0(%1)" | 322 | " lpswe 0(%1)" |
335 | : "=m" (ctl_buf) | 323 | : "=m" (ctl_buf) |
336 | : "a" (dw_psw), "a" (&ctl_buf), | 324 | : "a" (&dw_psw), "a" (&ctl_buf), |
337 | "m" (dw_psw) : "cc", "0", "1"); | 325 | "m" (dw_psw) : "cc", "0", "1"); |
338 | #endif /* __s390x__ */ | 326 | #endif /* __s390x__ */ |
339 | } | 327 | } |
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 4eff8f2e3bf1..fc7c96edc697 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h | |||
@@ -276,7 +276,7 @@ typedef struct | |||
276 | #endif /* __s390x__ */ | 276 | #endif /* __s390x__ */ |
277 | 277 | ||
278 | #define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ | 278 | #define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ |
279 | PSW_DEFAULT_KEY) | 279 | PSW_MASK_MCHECK | PSW_DEFAULT_KEY) |
280 | #define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ | 280 | #define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ |
281 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ | 281 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ |
282 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY) | 282 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY) |
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 81514d76edcf..e3cb3ce1d24a 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/types.h> | 16 | #include <asm/types.h> |
17 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
19 | #include <asm/processor.h> | ||
19 | 20 | ||
20 | #ifdef __KERNEL__ | 21 | #ifdef __KERNEL__ |
21 | 22 | ||
@@ -331,9 +332,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | |||
331 | 332 | ||
332 | #ifdef __s390x__ | 333 | #ifdef __s390x__ |
333 | 334 | ||
334 | #define __load_psw(psw) \ | ||
335 | __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); | ||
336 | |||
337 | #define __ctl_load(array, low, high) ({ \ | 335 | #define __ctl_load(array, low, high) ({ \ |
338 | typedef struct { char _[sizeof(array)]; } addrtype; \ | 336 | typedef struct { char _[sizeof(array)]; } addrtype; \ |
339 | __asm__ __volatile__ ( \ | 337 | __asm__ __volatile__ ( \ |
@@ -390,9 +388,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | |||
390 | 388 | ||
391 | #else /* __s390x__ */ | 389 | #else /* __s390x__ */ |
392 | 390 | ||
393 | #define __load_psw(psw) \ | ||
394 | __asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" ); | ||
395 | |||
396 | #define __ctl_load(array, low, high) ({ \ | 391 | #define __ctl_load(array, low, high) ({ \ |
397 | typedef struct { char _[sizeof(array)]; } addrtype; \ | 392 | typedef struct { char _[sizeof(array)]; } addrtype; \ |
398 | __asm__ __volatile__ ( \ | 393 | __asm__ __volatile__ ( \ |
@@ -451,6 +446,20 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | |||
451 | /* For spinlocks etc */ | 446 | /* For spinlocks etc */ |
452 | #define local_irq_save(x) ((x) = local_irq_disable()) | 447 | #define local_irq_save(x) ((x) = local_irq_disable()) |
453 | 448 | ||
449 | /* | ||
450 | * Use to set psw mask except for the first byte which | ||
451 | * won't be changed by this function. | ||
452 | */ | ||
453 | static inline void | ||
454 | __set_psw_mask(unsigned long mask) | ||
455 | { | ||
456 | local_save_flags(mask); | ||
457 | __load_psw_mask(mask); | ||
458 | } | ||
459 | |||
460 | #define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS) | ||
461 | #define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK) | ||
462 | |||
454 | #ifdef CONFIG_SMP | 463 | #ifdef CONFIG_SMP |
455 | 464 | ||
456 | extern void smp_ctl_set_bit(int cr, int bit); | 465 | extern void smp_ctl_set_bit(int cr, int bit); |
diff --git a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h index fe101d41e849..6c18a3f24316 100644 --- a/include/asm-s390/thread_info.h +++ b/include/asm-s390/thread_info.h | |||
@@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void) | |||
96 | #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ | 96 | #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ |
97 | #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ | 97 | #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ |
98 | #define TIF_SINGLE_STEP 6 /* deliver sigtrap on return to user */ | 98 | #define TIF_SINGLE_STEP 6 /* deliver sigtrap on return to user */ |
99 | #define TIF_MCCK_PENDING 7 /* machine check handling is pending */ | ||
99 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ | 100 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ |
100 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling | 101 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling |
101 | TIF_NEED_RESCHED */ | 102 | TIF_NEED_RESCHED */ |
@@ -109,6 +110,7 @@ static inline struct thread_info *current_thread_info(void) | |||
109 | #define _TIF_RESTART_SVC (1<<TIF_RESTART_SVC) | 110 | #define _TIF_RESTART_SVC (1<<TIF_RESTART_SVC) |
110 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 111 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
111 | #define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP) | 112 | #define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP) |
113 | #define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING) | ||
112 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) | 114 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) |
113 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 115 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
114 | #define _TIF_31BIT (1<<TIF_31BIT) | 116 | #define _TIF_31BIT (1<<TIF_31BIT) |