diff options
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 54 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/reipl.S | 17 | ||||
-rw-r--r-- | arch/s390/kernel/reipl64.S | 16 | ||||
-rw-r--r-- | arch/s390/kernel/relocate_kernel.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/relocate_kernel64.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/reset.S | 48 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 35 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 128 | ||||
-rw-r--r-- | include/asm-s390/cio.h | 4 | ||||
-rw-r--r-- | include/asm-s390/lowcore.h | 8 | ||||
-rw-r--r-- | include/asm-s390/reset.h | 23 |
13 files changed, 246 insertions, 108 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index aa978978d3d1..a81881c9b297 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | EXTRA_AFLAGS := -traditional | 5 | EXTRA_AFLAGS := -traditional |
6 | 6 | ||
7 | obj-y := bitmap.o traps.o time.o process.o \ | 7 | obj-y := bitmap.o traps.o time.o process.o reset.o \ |
8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ | 8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ |
9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o | 9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o |
10 | 10 | ||
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index ec127826f221..77f4aff630fe 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/cpcmd.h> | 19 | #include <asm/cpcmd.h> |
20 | #include <asm/cio.h> | 20 | #include <asm/cio.h> |
21 | #include <asm/ebcdic.h> | 21 | #include <asm/ebcdic.h> |
22 | #include <asm/reset.h> | ||
22 | 23 | ||
23 | #define IPL_PARM_BLOCK_VERSION 0 | 24 | #define IPL_PARM_BLOCK_VERSION 0 |
24 | #define LOADPARM_LEN 8 | 25 | #define LOADPARM_LEN 8 |
@@ -1024,3 +1025,56 @@ static int __init s390_ipl_init(void) | |||
1024 | } | 1025 | } |
1025 | 1026 | ||
1026 | __initcall(s390_ipl_init); | 1027 | __initcall(s390_ipl_init); |
1028 | |||
1029 | static LIST_HEAD(rcall); | ||
1030 | static DEFINE_MUTEX(rcall_mutex); | ||
1031 | |||
1032 | void register_reset_call(struct reset_call *reset) | ||
1033 | { | ||
1034 | mutex_lock(&rcall_mutex); | ||
1035 | list_add(&reset->list, &rcall); | ||
1036 | mutex_unlock(&rcall_mutex); | ||
1037 | } | ||
1038 | EXPORT_SYMBOL_GPL(register_reset_call); | ||
1039 | |||
1040 | void unregister_reset_call(struct reset_call *reset) | ||
1041 | { | ||
1042 | mutex_lock(&rcall_mutex); | ||
1043 | list_del(&reset->list); | ||
1044 | mutex_unlock(&rcall_mutex); | ||
1045 | } | ||
1046 | EXPORT_SYMBOL_GPL(unregister_reset_call); | ||
1047 | |||
1048 | static void do_reset_calls(void) | ||
1049 | { | ||
1050 | struct reset_call *reset; | ||
1051 | |||
1052 | list_for_each_entry(reset, &rcall, list) | ||
1053 | reset->fn(); | ||
1054 | } | ||
1055 | |||
1056 | extern void reset_mcck_handler(void); | ||
1057 | |||
1058 | void s390_reset_system(void) | ||
1059 | { | ||
1060 | struct _lowcore *lc; | ||
1061 | |||
1062 | /* Disable all interrupts/machine checks */ | ||
1063 | __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); | ||
1064 | |||
1065 | /* Stack for interrupt/machine check handler */ | ||
1066 | lc = (struct _lowcore *)(unsigned long) store_prefix(); | ||
1067 | lc->panic_stack = S390_lowcore.panic_stack; | ||
1068 | |||
1069 | /* Disable prefixing */ | ||
1070 | set_prefix(0); | ||
1071 | |||
1072 | /* Disable lowcore protection */ | ||
1073 | __ctl_clear_bit(0,28); | ||
1074 | |||
1075 | /* Set new machine check handler */ | ||
1076 | S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; | ||
1077 | S390_lowcore.mcck_new_psw.addr = | ||
1078 | PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; | ||
1079 | do_reset_calls(); | ||
1080 | } | ||
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 60b1ea9f946b..202bf1fdfe39 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/pgalloc.h> | 22 | #include <asm/pgalloc.h> |
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | #include <asm/smp.h> | 24 | #include <asm/smp.h> |
25 | #include <asm/reset.h> | ||
25 | 26 | ||
26 | static void kexec_halt_all_cpus(void *); | 27 | static void kexec_halt_all_cpus(void *); |
27 | 28 | ||
@@ -62,12 +63,6 @@ machine_shutdown(void) | |||
62 | NORET_TYPE void | 63 | NORET_TYPE void |
63 | machine_kexec(struct kimage *image) | 64 | machine_kexec(struct kimage *image) |
64 | { | 65 | { |
65 | clear_all_subchannels(); | ||
66 | cio_reset_channel_paths(); | ||
67 | |||
68 | /* Disable lowcore protection */ | ||
69 | ctl_clear_bit(0,28); | ||
70 | |||
71 | on_each_cpu(kexec_halt_all_cpus, image, 0, 0); | 66 | on_each_cpu(kexec_halt_all_cpus, image, 0, 0); |
72 | for (;;); | 67 | for (;;); |
73 | } | 68 | } |
@@ -98,6 +93,8 @@ kexec_halt_all_cpus(void *kernel_image) | |||
98 | cpu_relax(); | 93 | cpu_relax(); |
99 | } | 94 | } |
100 | 95 | ||
96 | s390_reset_system(); | ||
97 | |||
101 | image = (struct kimage *) kernel_image; | 98 | image = (struct kimage *) kernel_image; |
102 | data_mover = (relocate_kernel_t) | 99 | data_mover = (relocate_kernel_t) |
103 | (page_to_pfn(image->control_code_page) << PAGE_SHIFT); | 100 | (page_to_pfn(image->control_code_page) << PAGE_SHIFT); |
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 0340477f3b08..f9434d42ce9f 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S | |||
@@ -11,19 +11,10 @@ | |||
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) | 13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) |
14 | 14 | .Lpg1: # do store status of all registers | |
15 | # switch off lowcore protection | ||
16 | |||
17 | .Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
18 | stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13) | ||
19 | ni .Lctlsave1-.Lpg0(%r13),0xef | ||
20 | lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
21 | |||
22 | # do store status of all registers | ||
23 | 15 | ||
24 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA | 16 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA |
25 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA | 17 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA |
26 | mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13) | ||
27 | stam %a0,%a15,__LC_AREGS_SAVE_AREA | 18 | stam %a0,%a15,__LC_AREGS_SAVE_AREA |
28 | stpx __LC_PREFIX_SAVE_AREA | 19 | stpx __LC_PREFIX_SAVE_AREA |
29 | stckc .Lclkcmp-.Lpg0(%r13) | 20 | stckc .Lclkcmp-.Lpg0(%r13) |
@@ -56,8 +47,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 47 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 48 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 49 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 50 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lpsw 0 | 51 | lpsw 0 |
62 | sigp 0,0,0(6) | 52 | sigp 0,0,0(6) |
63 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) | 53 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) |
@@ -65,9 +55,6 @@ do_reipl_asm: basr %r13,0 | |||
65 | .align 8 | 55 | .align 8 |
66 | .Lclkcmp: .quad 0x0000000000000000 | 56 | .Lclkcmp: .quad 0x0000000000000000 |
67 | .Lall: .long 0xff000000 | 57 | .Lall: .long 0xff000000 |
68 | .Lnull: .long 0x00000000 | ||
69 | .Lctlsave1: .long 0x00000000 | ||
70 | .Lctlsave2: .long 0x00000000 | ||
71 | .align 8 | 58 | .align 8 |
72 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 | 59 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 |
73 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs | 60 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs |
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index de7435054f7c..f18ef260ca23 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S | |||
@@ -10,10 +10,10 @@ | |||
10 | #include <asm/lowcore.h> | 10 | #include <asm/lowcore.h> |
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) | ||
14 | .Lpg1: # do store status of all registers | ||
13 | 15 | ||
14 | # do store status of all registers | 16 | stg %r1,.Lregsave-.Lpg0(%r13) |
15 | |||
16 | .Lpg0: stg %r1,.Lregsave-.Lpg0(%r13) | ||
17 | lghi %r1,0x1000 | 17 | lghi %r1,0x1000 |
18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) | 18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) |
19 | lg %r0,.Lregsave-.Lpg0(%r13) | 19 | lg %r0,.Lregsave-.Lpg0(%r13) |
@@ -27,11 +27,7 @@ do_reipl_asm: basr %r13,0 | |||
27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) | 27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) |
28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) | 28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) |
29 | 29 | ||
30 | lpswe .Lnewpsw-.Lpg0(%r13) | 30 | lctlg %c6,%c6,.Lall-.Lpg0(%r13) |
31 | .Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) | ||
32 | stctg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
33 | ni .Lregsave+4-.Lpg0(%r13),0xef | ||
34 | lctlg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
35 | lgr %r1,%r2 | 31 | lgr %r1,%r2 |
36 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) | 32 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) |
37 | stsch .Lschib-.Lpg0(%r13) | 33 | stsch .Lschib-.Lpg0(%r13) |
@@ -56,8 +52,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 52 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 53 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 54 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 55 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lhi %r1,0 # mode 0 = esa | 56 | lhi %r1,0 # mode 0 = esa |
62 | slr %r0,%r0 # set cpuid to zero | 57 | slr %r0,%r0 # set cpuid to zero |
63 | sigp %r1,%r0,0x12 # switch to esa mode | 58 | sigp %r1,%r0,0x12 # switch to esa mode |
@@ -70,7 +65,6 @@ do_reipl_asm: basr %r13,0 | |||
70 | .Lclkcmp: .quad 0x0000000000000000 | 65 | .Lclkcmp: .quad 0x0000000000000000 |
71 | .Lall: .quad 0x00000000ff000000 | 66 | .Lall: .quad 0x00000000ff000000 |
72 | .Lregsave: .quad 0x0000000000000000 | 67 | .Lregsave: .quad 0x0000000000000000 |
73 | .Lnull: .long 0x0000000000000000 | ||
74 | .align 16 | 68 | .align 16 |
75 | /* | 69 | /* |
76 | * These addresses have to be 31 bit otherwise | 70 | * These addresses have to be 31 bit otherwise |
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index f9899ff2e5b0..3b456b80bcee 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S | |||
@@ -26,8 +26,7 @@ | |||
26 | relocate_kernel: | 26 | relocate_kernel: |
27 | basr %r13,0 # base address | 27 | basr %r13,0 # base address |
28 | .base: | 28 | .base: |
29 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) | 29 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
30 | spx zero64-.base(%r13) # absolute addressing mode | ||
31 | stctl %c0,%c15,ctlregs-.base(%r13) | 30 | stctl %c0,%c15,ctlregs-.base(%r13) |
32 | stm %r0,%r15,gprregs-.base(%r13) | 31 | stm %r0,%r15,gprregs-.base(%r13) |
33 | la %r1,load_psw-.base(%r13) | 32 | la %r1,load_psw-.base(%r13) |
@@ -97,8 +96,6 @@ | |||
97 | lpsw 0 # hopefully start new kernel... | 96 | lpsw 0 # hopefully start new kernel... |
98 | 97 | ||
99 | .align 8 | 98 | .align 8 |
100 | zero64: | ||
101 | .quad 0 | ||
102 | load_psw: | 99 | load_psw: |
103 | .long 0x00080000,0x80000000 | 100 | .long 0x00080000,0x80000000 |
104 | sys_msk: | 101 | sys_msk: |
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S index 4fb443042d9c..1f9ea2067b59 100644 --- a/arch/s390/kernel/relocate_kernel64.S +++ b/arch/s390/kernel/relocate_kernel64.S | |||
@@ -27,8 +27,7 @@ | |||
27 | relocate_kernel: | 27 | relocate_kernel: |
28 | basr %r13,0 # base address | 28 | basr %r13,0 # base address |
29 | .base: | 29 | .base: |
30 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs | 30 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
31 | spx zero64-.base(%r13) # absolute addressing mode | ||
32 | stctg %c0,%c15,ctlregs-.base(%r13) | 31 | stctg %c0,%c15,ctlregs-.base(%r13) |
33 | stmg %r0,%r15,gprregs-.base(%r13) | 32 | stmg %r0,%r15,gprregs-.base(%r13) |
34 | lghi %r0,3 | 33 | lghi %r0,3 |
@@ -100,8 +99,6 @@ | |||
100 | lpsw 0 # hopefully start new kernel... | 99 | lpsw 0 # hopefully start new kernel... |
101 | 100 | ||
102 | .align 8 | 101 | .align 8 |
103 | zero64: | ||
104 | .quad 0 | ||
105 | load_psw: | 102 | load_psw: |
106 | .long 0x00080000,0x80000000 | 103 | .long 0x00080000,0x80000000 |
107 | sys_msk: | 104 | sys_msk: |
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S new file mode 100644 index 000000000000..be8688c0665c --- /dev/null +++ b/arch/s390/kernel/reset.S | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * arch/s390/kernel/reset.S | ||
3 | * | ||
4 | * Copyright (C) IBM Corp. 2006 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <asm/ptrace.h> | ||
9 | #include <asm/lowcore.h> | ||
10 | |||
11 | #ifdef CONFIG_64BIT | ||
12 | |||
13 | .globl reset_mcck_handler | ||
14 | reset_mcck_handler: | ||
15 | basr %r13,0 | ||
16 | 0: lg %r15,__LC_PANIC_STACK # load panic stack | ||
17 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
18 | lg %r1,s390_reset_mcck_handler-0b(%r13) | ||
19 | ltgr %r1,%r1 | ||
20 | jz 1f | ||
21 | basr %r14,%r1 | ||
22 | 1: la %r1,4095 | ||
23 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) | ||
24 | lpswe __LC_MCK_OLD_PSW | ||
25 | |||
26 | .globl s390_reset_mcck_handler | ||
27 | s390_reset_mcck_handler: | ||
28 | .quad 0 | ||
29 | |||
30 | #else /* CONFIG_64BIT */ | ||
31 | |||
32 | .globl reset_mcck_handler | ||
33 | reset_mcck_handler: | ||
34 | basr %r13,0 | ||
35 | 0: l %r15,__LC_PANIC_STACK # load panic stack | ||
36 | ahi %r15,-STACK_FRAME_OVERHEAD | ||
37 | l %r1,s390_reset_mcck_handler-0b(%r13) | ||
38 | ltr %r1,%r1 | ||
39 | jz 1f | ||
40 | basr %r14,%r1 | ||
41 | 1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA | ||
42 | lpsw __LC_MCK_OLD_PSW | ||
43 | |||
44 | .globl s390_reset_mcck_handler | ||
45 | s390_reset_mcck_handler: | ||
46 | .long 0 | ||
47 | |||
48 | #endif /* CONFIG_64BIT */ | ||
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 2d78f0f4a40f..9d92540bd99e 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -1465,41 +1465,6 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) | |||
1465 | return desc; | 1465 | return desc; |
1466 | } | 1466 | } |
1467 | 1467 | ||
1468 | static int reset_channel_path(struct channel_path *chp) | ||
1469 | { | ||
1470 | int cc; | ||
1471 | |||
1472 | cc = rchp(chp->id); | ||
1473 | switch (cc) { | ||
1474 | case 0: | ||
1475 | return 0; | ||
1476 | case 2: | ||
1477 | return -EBUSY; | ||
1478 | default: | ||
1479 | return -ENODEV; | ||
1480 | } | ||
1481 | } | ||
1482 | |||
1483 | static void reset_channel_paths_css(struct channel_subsystem *css) | ||
1484 | { | ||
1485 | int i; | ||
1486 | |||
1487 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
1488 | if (css->chps[i]) | ||
1489 | reset_channel_path(css->chps[i]); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | void cio_reset_channel_paths(void) | ||
1494 | { | ||
1495 | int i; | ||
1496 | |||
1497 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
1498 | if (css[i] && css[i]->valid) | ||
1499 | reset_channel_paths_css(css[i]); | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | static int __init | 1468 | static int __init |
1504 | chsc_alloc_sei_area(void) | 1469 | chsc_alloc_sei_area(void) |
1505 | { | 1470 | { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8936e460a807..20aee2783847 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
22 | #include <asm/irq_regs.h> | 22 | #include <asm/irq_regs.h> |
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include <asm/reset.h> | ||
24 | #include "airq.h" | 25 | #include "airq.h" |
25 | #include "cio.h" | 26 | #include "cio.h" |
26 | #include "css.h" | 27 | #include "css.h" |
@@ -28,6 +29,7 @@ | |||
28 | #include "ioasm.h" | 29 | #include "ioasm.h" |
29 | #include "blacklist.h" | 30 | #include "blacklist.h" |
30 | #include "cio_debug.h" | 31 | #include "cio_debug.h" |
32 | #include "../s390mach.h" | ||
31 | 33 | ||
32 | debug_info_t *cio_debug_msg_id; | 34 | debug_info_t *cio_debug_msg_id; |
33 | debug_info_t *cio_debug_trace_id; | 35 | debug_info_t *cio_debug_trace_id; |
@@ -841,26 +843,12 @@ __clear_subchannel_easy(struct subchannel_id schid) | |||
841 | return -EBUSY; | 843 | return -EBUSY; |
842 | } | 844 | } |
843 | 845 | ||
844 | struct sch_match_id { | 846 | static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) |
845 | struct subchannel_id schid; | ||
846 | struct ccw_dev_id devid; | ||
847 | int rc; | ||
848 | }; | ||
849 | |||
850 | static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | ||
851 | void *data) | ||
852 | { | 847 | { |
853 | struct schib schib; | 848 | struct schib schib; |
854 | struct sch_match_id *match_id = data; | ||
855 | 849 | ||
856 | if (stsch_err(schid, &schib)) | 850 | if (stsch_err(schid, &schib)) |
857 | return -ENXIO; | 851 | return -ENXIO; |
858 | if (match_id && schib.pmcw.dnv && | ||
859 | (schib.pmcw.dev == match_id->devid.devno) && | ||
860 | (schid.ssid == match_id->devid.ssid)) { | ||
861 | match_id->schid = schid; | ||
862 | match_id->rc = 0; | ||
863 | } | ||
864 | if (!schib.pmcw.ena) | 852 | if (!schib.pmcw.ena) |
865 | return 0; | 853 | return 0; |
866 | switch(__disable_subchannel_easy(schid, &schib)) { | 854 | switch(__disable_subchannel_easy(schid, &schib)) { |
@@ -876,27 +864,111 @@ static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | |||
876 | return 0; | 864 | return 0; |
877 | } | 865 | } |
878 | 866 | ||
879 | static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, | 867 | static atomic_t chpid_reset_count; |
880 | struct subchannel_id *schid) | 868 | |
869 | static void s390_reset_chpids_mcck_handler(void) | ||
870 | { | ||
871 | struct crw crw; | ||
872 | struct mci *mci; | ||
873 | |||
874 | /* Check for pending channel report word. */ | ||
875 | mci = (struct mci *)&S390_lowcore.mcck_interruption_code; | ||
876 | if (!mci->cp) | ||
877 | return; | ||
878 | /* Process channel report words. */ | ||
879 | while (stcrw(&crw) == 0) { | ||
880 | /* Check for responses to RCHP. */ | ||
881 | if (crw.slct && crw.rsc == CRW_RSC_CPATH) | ||
882 | atomic_dec(&chpid_reset_count); | ||
883 | } | ||
884 | } | ||
885 | |||
886 | #define RCHP_TIMEOUT (30 * USEC_PER_SEC) | ||
887 | static void css_reset(void) | ||
888 | { | ||
889 | int i, ret; | ||
890 | unsigned long long timeout; | ||
891 | |||
892 | /* Reset subchannels. */ | ||
893 | for_each_subchannel(__shutdown_subchannel_easy, NULL); | ||
894 | /* Reset channel paths. */ | ||
895 | s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; | ||
896 | /* Enable channel report machine checks. */ | ||
897 | __ctl_set_bit(14, 28); | ||
898 | /* Temporarily reenable machine checks. */ | ||
899 | local_mcck_enable(); | ||
900 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
901 | ret = rchp(i); | ||
902 | if ((ret == 0) || (ret == 2)) | ||
903 | /* | ||
904 | * rchp either succeeded, or another rchp is already | ||
905 | * in progress. In either case, we'll get a crw. | ||
906 | */ | ||
907 | atomic_inc(&chpid_reset_count); | ||
908 | } | ||
909 | /* Wait for machine check for all channel paths. */ | ||
910 | timeout = get_clock() + (RCHP_TIMEOUT << 12); | ||
911 | while (atomic_read(&chpid_reset_count) != 0) { | ||
912 | if (get_clock() > timeout) | ||
913 | break; | ||
914 | cpu_relax(); | ||
915 | } | ||
916 | /* Disable machine checks again. */ | ||
917 | local_mcck_disable(); | ||
918 | /* Disable channel report machine checks. */ | ||
919 | __ctl_clear_bit(14, 28); | ||
920 | s390_reset_mcck_handler = NULL; | ||
921 | } | ||
922 | |||
923 | static struct reset_call css_reset_call = { | ||
924 | .fn = css_reset, | ||
925 | }; | ||
926 | |||
927 | static int __init init_css_reset_call(void) | ||
928 | { | ||
929 | atomic_set(&chpid_reset_count, 0); | ||
930 | register_reset_call(&css_reset_call); | ||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | arch_initcall(init_css_reset_call); | ||
935 | |||
936 | struct sch_match_id { | ||
937 | struct subchannel_id schid; | ||
938 | struct ccw_dev_id devid; | ||
939 | int rc; | ||
940 | }; | ||
941 | |||
942 | static int __reipl_subchannel_match(struct subchannel_id schid, void *data) | ||
943 | { | ||
944 | struct schib schib; | ||
945 | struct sch_match_id *match_id = data; | ||
946 | |||
947 | if (stsch_err(schid, &schib)) | ||
948 | return -ENXIO; | ||
949 | if (schib.pmcw.dnv && | ||
950 | (schib.pmcw.dev == match_id->devid.devno) && | ||
951 | (schid.ssid == match_id->devid.ssid)) { | ||
952 | match_id->schid = schid; | ||
953 | match_id->rc = 0; | ||
954 | return 1; | ||
955 | } | ||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static int reipl_find_schid(struct ccw_dev_id *devid, | ||
960 | struct subchannel_id *schid) | ||
881 | { | 961 | { |
882 | struct sch_match_id match_id; | 962 | struct sch_match_id match_id; |
883 | 963 | ||
884 | match_id.devid = *devid; | 964 | match_id.devid = *devid; |
885 | match_id.rc = -ENODEV; | 965 | match_id.rc = -ENODEV; |
886 | local_irq_disable(); | 966 | for_each_subchannel(__reipl_subchannel_match, &match_id); |
887 | for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id); | ||
888 | if (match_id.rc == 0) | 967 | if (match_id.rc == 0) |
889 | *schid = match_id.schid; | 968 | *schid = match_id.schid; |
890 | return match_id.rc; | 969 | return match_id.rc; |
891 | } | 970 | } |
892 | 971 | ||
893 | |||
894 | void clear_all_subchannels(void) | ||
895 | { | ||
896 | local_irq_disable(); | ||
897 | for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL); | ||
898 | } | ||
899 | |||
900 | extern void do_reipl_asm(__u32 schid); | 972 | extern void do_reipl_asm(__u32 schid); |
901 | 973 | ||
902 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 974 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
@@ -904,9 +976,9 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) | |||
904 | { | 976 | { |
905 | struct subchannel_id schid; | 977 | struct subchannel_id schid; |
906 | 978 | ||
907 | if (clear_all_subchannels_and_match(devid, &schid)) | 979 | s390_reset_system(); |
980 | if (reipl_find_schid(devid, &schid) != 0) | ||
908 | panic("IPL Device not found\n"); | 981 | panic("IPL Device not found\n"); |
909 | cio_reset_channel_paths(); | ||
910 | do_reipl_asm(*((__u32*)&schid)); | 982 | do_reipl_asm(*((__u32*)&schid)); |
911 | } | 983 | } |
912 | 984 | ||
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 81287d86329d..cabd5bb74b5a 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h | |||
@@ -285,10 +285,6 @@ extern int diag210(struct diag210 *addr); | |||
285 | 285 | ||
286 | extern void wait_cons_dev(void); | 286 | extern void wait_cons_dev(void); |
287 | 287 | ||
288 | extern void clear_all_subchannels(void); | ||
289 | |||
290 | extern void cio_reset_channel_paths(void); | ||
291 | |||
292 | extern void css_schedule_reprobe(void); | 288 | extern void css_schedule_reprobe(void); |
293 | 289 | ||
294 | extern void reipl_ccw_dev(struct ccw_dev_id *id); | 290 | extern void reipl_ccw_dev(struct ccw_dev_id *id); |
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 06583ed0bde7..74f7389bd3ee 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h | |||
@@ -362,6 +362,14 @@ static inline void set_prefix(__u32 address) | |||
362 | asm volatile("spx %0" : : "m" (address) : "memory"); | 362 | asm volatile("spx %0" : : "m" (address) : "memory"); |
363 | } | 363 | } |
364 | 364 | ||
365 | static inline __u32 store_prefix(void) | ||
366 | { | ||
367 | __u32 address; | ||
368 | |||
369 | asm volatile("stpx %0" : "=m" (address)); | ||
370 | return address; | ||
371 | } | ||
372 | |||
365 | #define __PANIC_MAGIC 0xDEADC0DE | 373 | #define __PANIC_MAGIC 0xDEADC0DE |
366 | 374 | ||
367 | #endif | 375 | #endif |
diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h new file mode 100644 index 000000000000..9b439cf67800 --- /dev/null +++ b/include/asm-s390/reset.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * include/asm-s390/reset.h | ||
3 | * | ||
4 | * Copyright IBM Corp. 2006 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef _ASM_S390_RESET_H | ||
9 | #define _ASM_S390_RESET_H | ||
10 | |||
11 | #include <linux/list.h> | ||
12 | |||
13 | struct reset_call { | ||
14 | struct list_head list; | ||
15 | void (*fn)(void); | ||
16 | }; | ||
17 | |||
18 | extern void register_reset_call(struct reset_call *reset); | ||
19 | extern void unregister_reset_call(struct reset_call *reset); | ||
20 | extern void s390_reset_system(void); | ||
21 | extern void (*s390_reset_mcck_handler)(void); | ||
22 | |||
23 | #endif /* _ASM_S390_RESET_H */ | ||