diff options
Diffstat (limited to 'arch/ia64/kernel/crash.c')
-rw-r--r-- | arch/ia64/kernel/crash.c | 83 |
1 files changed, 57 insertions, 26 deletions
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index f065093f8e9b..6631a9dfafdc 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c | |||
@@ -23,6 +23,7 @@ | |||
23 | int kdump_status[NR_CPUS]; | 23 | int kdump_status[NR_CPUS]; |
24 | static atomic_t kdump_cpu_frozen; | 24 | static atomic_t kdump_cpu_frozen; |
25 | atomic_t kdump_in_progress; | 25 | atomic_t kdump_in_progress; |
26 | static int kdump_freeze_monarch; | ||
26 | static int kdump_on_init = 1; | 27 | static int kdump_on_init = 1; |
27 | static int kdump_on_fatal_mca = 1; | 28 | static int kdump_on_fatal_mca = 1; |
28 | 29 | ||
@@ -108,10 +109,38 @@ machine_crash_shutdown(struct pt_regs *pt) | |||
108 | */ | 109 | */ |
109 | kexec_disable_iosapic(); | 110 | kexec_disable_iosapic(); |
110 | #ifdef CONFIG_SMP | 111 | #ifdef CONFIG_SMP |
112 | /* | ||
113 | * If kdump_on_init is set and an INIT is asserted here, kdump will | ||
114 | * be started again via INIT monarch. | ||
115 | */ | ||
116 | local_irq_disable(); | ||
117 | ia64_set_psr_mc(); /* mask MCA/INIT */ | ||
118 | if (atomic_inc_return(&kdump_in_progress) != 1) | ||
119 | unw_init_running(kdump_cpu_freeze, NULL); | ||
120 | |||
121 | /* | ||
122 | * Now this cpu is ready for kdump. | ||
123 | * Stop all others by IPI or INIT. They could receive INIT from | ||
124 | * outside and might be INIT monarch, but only thing they have to | ||
125 | * do is falling into kdump_cpu_freeze(). | ||
126 | * | ||
127 | * If an INIT is asserted here: | ||
128 | * - All receivers might be slaves, since some of cpus could already | ||
129 | * be frozen and INIT might be masked on monarch. In this case, | ||
130 | * all slaves will be frozen soon since kdump_in_progress will let | ||
131 | * them into DIE_INIT_SLAVE_LEAVE. | ||
132 | * - One might be a monarch, but INIT rendezvous will fail since | ||
133 | * at least this cpu already have INIT masked so it never join | ||
134 | * to the rendezvous. In this case, all slaves and monarch will | ||
135 | * be frozen soon with no wait since the INIT rendezvous is skipped | ||
136 | * by kdump_in_progress. | ||
137 | */ | ||
111 | kdump_smp_send_stop(); | 138 | kdump_smp_send_stop(); |
112 | /* not all cpu response to IPI, send INIT to freeze them */ | 139 | /* not all cpu response to IPI, send INIT to freeze them */ |
113 | if (kdump_wait_cpu_freeze() && kdump_on_init) { | 140 | if (kdump_wait_cpu_freeze()) { |
114 | kdump_smp_send_init(); | 141 | kdump_smp_send_init(); |
142 | /* wait again, don't go ahead if possible */ | ||
143 | kdump_wait_cpu_freeze(); | ||
115 | } | 144 | } |
116 | #endif | 145 | #endif |
117 | } | 146 | } |
@@ -129,17 +158,17 @@ void | |||
129 | kdump_cpu_freeze(struct unw_frame_info *info, void *arg) | 158 | kdump_cpu_freeze(struct unw_frame_info *info, void *arg) |
130 | { | 159 | { |
131 | int cpuid; | 160 | int cpuid; |
161 | |||
132 | local_irq_disable(); | 162 | local_irq_disable(); |
133 | cpuid = smp_processor_id(); | 163 | cpuid = smp_processor_id(); |
134 | crash_save_this_cpu(); | 164 | crash_save_this_cpu(); |
135 | current->thread.ksp = (__u64)info->sw - 16; | 165 | current->thread.ksp = (__u64)info->sw - 16; |
166 | |||
167 | ia64_set_psr_mc(); /* mask MCA/INIT and stop reentrance */ | ||
168 | |||
136 | atomic_inc(&kdump_cpu_frozen); | 169 | atomic_inc(&kdump_cpu_frozen); |
137 | kdump_status[cpuid] = 1; | 170 | kdump_status[cpuid] = 1; |
138 | mb(); | 171 | mb(); |
139 | #ifdef CONFIG_HOTPLUG_CPU | ||
140 | if (cpuid != 0) | ||
141 | ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); | ||
142 | #endif | ||
143 | for (;;) | 172 | for (;;) |
144 | cpu_relax(); | 173 | cpu_relax(); |
145 | } | 174 | } |
@@ -150,6 +179,20 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) | |||
150 | struct ia64_mca_notify_die *nd; | 179 | struct ia64_mca_notify_die *nd; |
151 | struct die_args *args = data; | 180 | struct die_args *args = data; |
152 | 181 | ||
182 | if (atomic_read(&kdump_in_progress)) { | ||
183 | switch (val) { | ||
184 | case DIE_INIT_MONARCH_LEAVE: | ||
185 | if (!kdump_freeze_monarch) | ||
186 | break; | ||
187 | /* fall through */ | ||
188 | case DIE_INIT_SLAVE_LEAVE: | ||
189 | case DIE_INIT_MONARCH_ENTER: | ||
190 | case DIE_MCA_RENDZVOUS_LEAVE: | ||
191 | unw_init_running(kdump_cpu_freeze, NULL); | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
153 | if (!kdump_on_init && !kdump_on_fatal_mca) | 196 | if (!kdump_on_init && !kdump_on_fatal_mca) |
154 | return NOTIFY_DONE; | 197 | return NOTIFY_DONE; |
155 | 198 | ||
@@ -162,43 +205,31 @@ kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) | |||
162 | } | 205 | } |
163 | 206 | ||
164 | if (val != DIE_INIT_MONARCH_LEAVE && | 207 | if (val != DIE_INIT_MONARCH_LEAVE && |
165 | val != DIE_INIT_SLAVE_LEAVE && | ||
166 | val != DIE_INIT_MONARCH_PROCESS && | 208 | val != DIE_INIT_MONARCH_PROCESS && |
167 | val != DIE_MCA_RENDZVOUS_LEAVE && | ||
168 | val != DIE_MCA_MONARCH_LEAVE) | 209 | val != DIE_MCA_MONARCH_LEAVE) |
169 | return NOTIFY_DONE; | 210 | return NOTIFY_DONE; |
170 | 211 | ||
171 | nd = (struct ia64_mca_notify_die *)args->err; | 212 | nd = (struct ia64_mca_notify_die *)args->err; |
172 | /* Reason code 1 means machine check rendezvous*/ | ||
173 | if ((val == DIE_INIT_MONARCH_LEAVE || val == DIE_INIT_SLAVE_LEAVE | ||
174 | || val == DIE_INIT_MONARCH_PROCESS) && nd->sos->rv_rc == 1) | ||
175 | return NOTIFY_DONE; | ||
176 | 213 | ||
177 | switch (val) { | 214 | switch (val) { |
178 | case DIE_INIT_MONARCH_PROCESS: | 215 | case DIE_INIT_MONARCH_PROCESS: |
179 | if (kdump_on_init) { | 216 | /* Reason code 1 means machine check rendezvous*/ |
180 | atomic_set(&kdump_in_progress, 1); | 217 | if (kdump_on_init && (nd->sos->rv_rc != 1)) { |
181 | *(nd->monarch_cpu) = -1; | 218 | if (atomic_inc_return(&kdump_in_progress) != 1) |
219 | kdump_freeze_monarch = 1; | ||
182 | } | 220 | } |
183 | break; | 221 | break; |
184 | case DIE_INIT_MONARCH_LEAVE: | 222 | case DIE_INIT_MONARCH_LEAVE: |
185 | if (kdump_on_init) | 223 | /* Reason code 1 means machine check rendezvous*/ |
224 | if (kdump_on_init && (nd->sos->rv_rc != 1)) | ||
186 | machine_kdump_on_init(); | 225 | machine_kdump_on_init(); |
187 | break; | 226 | break; |
188 | case DIE_INIT_SLAVE_LEAVE: | ||
189 | if (atomic_read(&kdump_in_progress)) | ||
190 | unw_init_running(kdump_cpu_freeze, NULL); | ||
191 | break; | ||
192 | case DIE_MCA_RENDZVOUS_LEAVE: | ||
193 | if (atomic_read(&kdump_in_progress)) | ||
194 | unw_init_running(kdump_cpu_freeze, NULL); | ||
195 | break; | ||
196 | case DIE_MCA_MONARCH_LEAVE: | 227 | case DIE_MCA_MONARCH_LEAVE: |
197 | /* *(nd->data) indicate if MCA is recoverable */ | 228 | /* *(nd->data) indicate if MCA is recoverable */ |
198 | if (kdump_on_fatal_mca && !(*(nd->data))) { | 229 | if (kdump_on_fatal_mca && !(*(nd->data))) { |
199 | atomic_set(&kdump_in_progress, 1); | 230 | if (atomic_inc_return(&kdump_in_progress) == 1) |
200 | *(nd->monarch_cpu) = -1; | 231 | machine_kdump_on_init(); |
201 | machine_kdump_on_init(); | 232 | /* We got fatal MCA while kdump!? No way!! */ |
202 | } | 233 | } |
203 | break; | 234 | break; |
204 | } | 235 | } |