aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/crash.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/crash.c')
-rw-r--r--arch/ia64/kernel/crash.c83
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 @@
23int kdump_status[NR_CPUS]; 23int kdump_status[NR_CPUS];
24static atomic_t kdump_cpu_frozen; 24static atomic_t kdump_cpu_frozen;
25atomic_t kdump_in_progress; 25atomic_t kdump_in_progress;
26static int kdump_freeze_monarch;
26static int kdump_on_init = 1; 27static int kdump_on_init = 1;
27static int kdump_on_fatal_mca = 1; 28static 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
129kdump_cpu_freeze(struct unw_frame_info *info, void *arg) 158kdump_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 }