Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/kernel/crash.c
10817 views
1
/*
2
* Architecture specific (PPC64) functions for kexec based crash dumps.
3
*
4
* Copyright (C) 2005, IBM Corp.
5
*
6
* Created by: Haren Myneni
7
*
8
* This source code is licensed under the GNU General Public License,
9
* Version 2. See the file COPYING for more details.
10
*
11
*/
12
13
#undef DEBUG
14
15
#include <linux/kernel.h>
16
#include <linux/smp.h>
17
#include <linux/reboot.h>
18
#include <linux/kexec.h>
19
#include <linux/bootmem.h>
20
#include <linux/crash_dump.h>
21
#include <linux/delay.h>
22
#include <linux/elf.h>
23
#include <linux/elfcore.h>
24
#include <linux/init.h>
25
#include <linux/irq.h>
26
#include <linux/types.h>
27
#include <linux/memblock.h>
28
29
#include <asm/processor.h>
30
#include <asm/machdep.h>
31
#include <asm/kexec.h>
32
#include <asm/kdump.h>
33
#include <asm/prom.h>
34
#include <asm/firmware.h>
35
#include <asm/smp.h>
36
#include <asm/system.h>
37
#include <asm/setjmp.h>
38
39
#ifdef DEBUG
40
#include <asm/udbg.h>
41
#define DBG(fmt...) udbg_printf(fmt)
42
#else
43
#define DBG(fmt...)
44
#endif
45
46
/* This keeps a track of which one is crashing cpu. */
47
int crashing_cpu = -1;
48
static cpumask_t cpus_in_crash = CPU_MASK_NONE;
49
cpumask_t cpus_in_sr = CPU_MASK_NONE;
50
51
#define CRASH_HANDLER_MAX 3
52
/* NULL terminated list of shutdown handles */
53
static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1];
54
static DEFINE_SPINLOCK(crash_handlers_lock);
55
56
#ifdef CONFIG_SMP
57
static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
58
59
void crash_ipi_callback(struct pt_regs *regs)
60
{
61
int cpu = smp_processor_id();
62
63
if (!cpu_online(cpu))
64
return;
65
66
hard_irq_disable();
67
if (!cpumask_test_cpu(cpu, &cpus_in_crash))
68
crash_save_cpu(regs, cpu);
69
cpumask_set_cpu(cpu, &cpus_in_crash);
70
71
/*
72
* Entered via soft-reset - could be the kdump
73
* process is invoked using soft-reset or user activated
74
* it if some CPU did not respond to an IPI.
75
* For soft-reset, the secondary CPU can enter this func
76
* twice. 1 - using IPI, and 2. soft-reset.
77
* Tell the kexec CPU that entered via soft-reset and ready
78
* to go down.
79
*/
80
if (cpumask_test_cpu(cpu, &cpus_in_sr)) {
81
cpumask_clear_cpu(cpu, &cpus_in_sr);
82
atomic_inc(&enter_on_soft_reset);
83
}
84
85
/*
86
* Starting the kdump boot.
87
* This barrier is needed to make sure that all CPUs are stopped.
88
* If not, soft-reset will be invoked to bring other CPUs.
89
*/
90
while (!cpumask_test_cpu(crashing_cpu, &cpus_in_crash))
91
cpu_relax();
92
93
if (ppc_md.kexec_cpu_down)
94
ppc_md.kexec_cpu_down(1, 1);
95
96
#ifdef CONFIG_PPC64
97
kexec_smp_wait();
98
#else
99
for (;;); /* FIXME */
100
#endif
101
102
/* NOTREACHED */
103
}
104
105
/*
106
* Wait until all CPUs are entered via soft-reset.
107
*/
108
static void crash_soft_reset_check(int cpu)
109
{
110
unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
111
112
cpumask_clear_cpu(cpu, &cpus_in_sr);
113
while (atomic_read(&enter_on_soft_reset) != ncpus)
114
cpu_relax();
115
}
116
117
118
static void crash_kexec_prepare_cpus(int cpu)
119
{
120
unsigned int msecs;
121
122
unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
123
124
crash_send_ipi(crash_ipi_callback);
125
smp_wmb();
126
127
/*
128
* FIXME: Until we will have the way to stop other CPUs reliably,
129
* the crash CPU will send an IPI and wait for other CPUs to
130
* respond.
131
* Delay of at least 10 seconds.
132
*/
133
printk(KERN_EMERG "Sending IPI to other cpus...\n");
134
msecs = 10000;
135
while ((cpumask_weight(&cpus_in_crash) < ncpus) && (--msecs > 0)) {
136
cpu_relax();
137
mdelay(1);
138
}
139
140
/* Would it be better to replace the trap vector here? */
141
142
/*
143
* FIXME: In case if we do not get all CPUs, one possibility: ask the
144
* user to do soft reset such that we get all.
145
* Soft-reset will be used until better mechanism is implemented.
146
*/
147
if (cpumask_weight(&cpus_in_crash) < ncpus) {
148
printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
149
ncpus - cpumask_weight(&cpus_in_crash));
150
printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
151
cpumask_clear(&cpus_in_sr);
152
atomic_set(&enter_on_soft_reset, 0);
153
while (cpumask_weight(&cpus_in_crash) < ncpus)
154
cpu_relax();
155
}
156
/*
157
* Make sure all CPUs are entered via soft-reset if the kdump is
158
* invoked using soft-reset.
159
*/
160
if (cpumask_test_cpu(cpu, &cpus_in_sr))
161
crash_soft_reset_check(cpu);
162
/* Leave the IPI callback set */
163
}
164
165
/*
166
* This function will be called by secondary cpus or by kexec cpu
167
* if soft-reset is activated to stop some CPUs.
168
*/
169
void crash_kexec_secondary(struct pt_regs *regs)
170
{
171
int cpu = smp_processor_id();
172
unsigned long flags;
173
int msecs = 5;
174
175
local_irq_save(flags);
176
/* Wait 5ms if the kexec CPU is not entered yet. */
177
while (crashing_cpu < 0) {
178
if (--msecs < 0) {
179
/*
180
* Either kdump image is not loaded or
181
* kdump process is not started - Probably xmon
182
* exited using 'x'(exit and recover) or
183
* kexec_should_crash() failed for all running tasks.
184
*/
185
cpumask_clear_cpu(cpu, &cpus_in_sr);
186
local_irq_restore(flags);
187
return;
188
}
189
mdelay(1);
190
cpu_relax();
191
}
192
if (cpu == crashing_cpu) {
193
/*
194
* Panic CPU will enter this func only via soft-reset.
195
* Wait until all secondary CPUs entered and
196
* then start kexec boot.
197
*/
198
crash_soft_reset_check(cpu);
199
cpumask_set_cpu(crashing_cpu, &cpus_in_crash);
200
if (ppc_md.kexec_cpu_down)
201
ppc_md.kexec_cpu_down(1, 0);
202
machine_kexec(kexec_crash_image);
203
/* NOTREACHED */
204
}
205
crash_ipi_callback(regs);
206
}
207
208
#else /* ! CONFIG_SMP */
209
210
static void crash_kexec_prepare_cpus(int cpu)
211
{
212
/*
213
* move the secondarys to us so that we can copy
214
* the new kernel 0-0x100 safely
215
*
216
* do this if kexec in setup.c ?
217
*/
218
#ifdef CONFIG_PPC64
219
smp_release_cpus();
220
#else
221
/* FIXME */
222
#endif
223
}
224
225
void crash_kexec_secondary(struct pt_regs *regs)
226
{
227
cpumask_clear(&cpus_in_sr);
228
}
229
#endif /* CONFIG_SMP */
230
231
/* wait for all the CPUs to hit real mode but timeout if they don't come in */
232
#if defined(CONFIG_SMP) && defined(CONFIG_PPC_STD_MMU_64)
233
static void crash_kexec_wait_realmode(int cpu)
234
{
235
unsigned int msecs;
236
int i;
237
238
msecs = 10000;
239
for (i=0; i < nr_cpu_ids && msecs > 0; i++) {
240
if (i == cpu)
241
continue;
242
243
while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
244
barrier();
245
if (!cpu_possible(i)) {
246
break;
247
}
248
if (!cpu_online(i)) {
249
break;
250
}
251
msecs--;
252
mdelay(1);
253
}
254
}
255
mb();
256
}
257
#else
258
static inline void crash_kexec_wait_realmode(int cpu) {}
259
#endif /* CONFIG_SMP && CONFIG_PPC_STD_MMU_64 */
260
261
/*
262
* Register a function to be called on shutdown. Only use this if you
263
* can't reset your device in the second kernel.
264
*/
265
int crash_shutdown_register(crash_shutdown_t handler)
266
{
267
unsigned int i, rc;
268
269
spin_lock(&crash_handlers_lock);
270
for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
271
if (!crash_shutdown_handles[i]) {
272
/* Insert handle at first empty entry */
273
crash_shutdown_handles[i] = handler;
274
rc = 0;
275
break;
276
}
277
278
if (i == CRASH_HANDLER_MAX) {
279
printk(KERN_ERR "Crash shutdown handles full, "
280
"not registered.\n");
281
rc = 1;
282
}
283
284
spin_unlock(&crash_handlers_lock);
285
return rc;
286
}
287
EXPORT_SYMBOL(crash_shutdown_register);
288
289
int crash_shutdown_unregister(crash_shutdown_t handler)
290
{
291
unsigned int i, rc;
292
293
spin_lock(&crash_handlers_lock);
294
for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
295
if (crash_shutdown_handles[i] == handler)
296
break;
297
298
if (i == CRASH_HANDLER_MAX) {
299
printk(KERN_ERR "Crash shutdown handle not found\n");
300
rc = 1;
301
} else {
302
/* Shift handles down */
303
for (; crash_shutdown_handles[i]; i++)
304
crash_shutdown_handles[i] =
305
crash_shutdown_handles[i+1];
306
rc = 0;
307
}
308
309
spin_unlock(&crash_handlers_lock);
310
return rc;
311
}
312
EXPORT_SYMBOL(crash_shutdown_unregister);
313
314
static unsigned long crash_shutdown_buf[JMP_BUF_LEN];
315
static int crash_shutdown_cpu = -1;
316
317
static int handle_fault(struct pt_regs *regs)
318
{
319
if (crash_shutdown_cpu == smp_processor_id())
320
longjmp(crash_shutdown_buf, 1);
321
return 0;
322
}
323
324
void default_machine_crash_shutdown(struct pt_regs *regs)
325
{
326
unsigned int i;
327
int (*old_handler)(struct pt_regs *regs);
328
329
330
/*
331
* This function is only called after the system
332
* has panicked or is otherwise in a critical state.
333
* The minimum amount of code to allow a kexec'd kernel
334
* to run successfully needs to happen here.
335
*
336
* In practice this means stopping other cpus in
337
* an SMP system.
338
* The kernel is broken so disable interrupts.
339
*/
340
hard_irq_disable();
341
342
/*
343
* Make a note of crashing cpu. Will be used in machine_kexec
344
* such that another IPI will not be sent.
345
*/
346
crashing_cpu = smp_processor_id();
347
crash_save_cpu(regs, crashing_cpu);
348
crash_kexec_prepare_cpus(crashing_cpu);
349
cpumask_set_cpu(crashing_cpu, &cpus_in_crash);
350
crash_kexec_wait_realmode(crashing_cpu);
351
352
machine_kexec_mask_interrupts();
353
354
/*
355
* Call registered shutdown routines savely. Swap out
356
* __debugger_fault_handler, and replace on exit.
357
*/
358
old_handler = __debugger_fault_handler;
359
__debugger_fault_handler = handle_fault;
360
crash_shutdown_cpu = smp_processor_id();
361
for (i = 0; crash_shutdown_handles[i]; i++) {
362
if (setjmp(crash_shutdown_buf) == 0) {
363
/*
364
* Insert syncs and delay to ensure
365
* instructions in the dangerous region don't
366
* leak away from this protected region.
367
*/
368
asm volatile("sync; isync");
369
/* dangerous region */
370
crash_shutdown_handles[i]();
371
asm volatile("sync; isync");
372
}
373
}
374
crash_shutdown_cpu = -1;
375
__debugger_fault_handler = old_handler;
376
377
if (ppc_md.kexec_cpu_down)
378
ppc_md.kexec_cpu_down(1, 0);
379
}
380
381