diff options
author | Anton Blanchard <anton@samba.org> | 2011-11-29 19:23:17 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-12-07 22:02:24 -0500 |
commit | 2440c01e10f07adcbc2094ba12ae4ad6094bd2b6 (patch) | |
tree | 5e14335ea80cf627a3037f348d4675d2ffa980ba /arch/powerpc/kernel | |
parent | 549e88a134b3b393a4312e8d76628b9260eee57f (diff) |
powerpc/kdump: Only save CPU state first time through the secondary CPU capture code
We might enter the secondary CPU capture code twice, eg if we have to
unstick some CPUs with a system reset. In this case we don't want to
overwrite the state on CPUs that had made it into the capture code OK,
so use the cpus_state_saved cpumask for that and make it local to
crash_ipi_callback.
For controlling progress now use atomic_t cpus_in_crash to count how
many CPUs have made it into the kdump code, and time_to_dump to tell
everyone it's time to dump.
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/crash.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index b942980e9650..28be3452e67a 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -46,7 +46,8 @@ | |||
46 | 46 | ||
47 | /* This keeps a track of which one is the crashing cpu. */ | 47 | /* This keeps a track of which one is the crashing cpu. */ |
48 | int crashing_cpu = -1; | 48 | int crashing_cpu = -1; |
49 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; | 49 | static atomic_t cpus_in_crash; |
50 | static int time_to_dump; | ||
50 | 51 | ||
51 | #define CRASH_HANDLER_MAX 3 | 52 | #define CRASH_HANDLER_MAX 3 |
52 | /* NULL terminated list of shutdown handles */ | 53 | /* NULL terminated list of shutdown handles */ |
@@ -67,21 +68,27 @@ static int handle_fault(struct pt_regs *regs) | |||
67 | 68 | ||
68 | void crash_ipi_callback(struct pt_regs *regs) | 69 | void crash_ipi_callback(struct pt_regs *regs) |
69 | { | 70 | { |
71 | static cpumask_t cpus_state_saved = CPU_MASK_NONE; | ||
72 | |||
70 | int cpu = smp_processor_id(); | 73 | int cpu = smp_processor_id(); |
71 | 74 | ||
72 | if (!cpu_online(cpu)) | 75 | if (!cpu_online(cpu)) |
73 | return; | 76 | return; |
74 | 77 | ||
75 | hard_irq_disable(); | 78 | hard_irq_disable(); |
76 | if (!cpumask_test_cpu(cpu, &cpus_in_crash)) | 79 | if (!cpumask_test_cpu(cpu, &cpus_state_saved)) { |
77 | crash_save_cpu(regs, cpu); | 80 | crash_save_cpu(regs, cpu); |
78 | cpumask_set_cpu(cpu, &cpus_in_crash); | 81 | cpumask_set_cpu(cpu, &cpus_state_saved); |
82 | } | ||
83 | |||
84 | atomic_inc(&cpus_in_crash); | ||
85 | smp_mb__after_atomic_inc(); | ||
79 | 86 | ||
80 | /* | 87 | /* |
81 | * Starting the kdump boot. | 88 | * Starting the kdump boot. |
82 | * This barrier is needed to make sure that all CPUs are stopped. | 89 | * This barrier is needed to make sure that all CPUs are stopped. |
83 | */ | 90 | */ |
84 | while (!cpumask_test_cpu(crashing_cpu, &cpus_in_crash)) | 91 | while (!time_to_dump) |
85 | cpu_relax(); | 92 | cpu_relax(); |
86 | 93 | ||
87 | if (ppc_md.kexec_cpu_down) | 94 | if (ppc_md.kexec_cpu_down) |
@@ -115,19 +122,18 @@ again: | |||
115 | * respond. | 122 | * respond. |
116 | */ | 123 | */ |
117 | msecs = IPI_TIMEOUT; | 124 | msecs = IPI_TIMEOUT; |
118 | while ((cpumask_weight(&cpus_in_crash) < ncpus) && (--msecs > 0)) { | 125 | while ((atomic_read(&cpus_in_crash) < ncpus) && (--msecs > 0)) |
119 | mdelay(1); | 126 | mdelay(1); |
120 | } | ||
121 | 127 | ||
122 | /* Would it be better to replace the trap vector here? */ | 128 | /* Would it be better to replace the trap vector here? */ |
123 | 129 | ||
124 | if (cpumask_weight(&cpus_in_crash) >= ncpus) { | 130 | if (atomic_read(&cpus_in_crash) >= ncpus) { |
125 | printk(KERN_EMERG "IPI complete\n"); | 131 | printk(KERN_EMERG "IPI complete\n"); |
126 | return; | 132 | return; |
127 | } | 133 | } |
128 | 134 | ||
129 | printk(KERN_EMERG "ERROR: %d cpu(s) not responding\n", | 135 | printk(KERN_EMERG "ERROR: %d cpu(s) not responding\n", |
130 | ncpus - cpumask_weight(&cpus_in_crash)); | 136 | ncpus - atomic_read(&cpus_in_crash)); |
131 | 137 | ||
132 | /* | 138 | /* |
133 | * If we have a panic timeout set then we can't wait indefinitely | 139 | * If we have a panic timeout set then we can't wait indefinitely |
@@ -155,10 +161,10 @@ again: | |||
155 | * crash code again. We need to reset cpus_in_crash so we | 161 | * crash code again. We need to reset cpus_in_crash so we |
156 | * wait for everyone to do this. | 162 | * wait for everyone to do this. |
157 | */ | 163 | */ |
158 | cpus_in_crash = CPU_MASK_NONE; | 164 | atomic_set(&cpus_in_crash, 0); |
159 | smp_mb(); | 165 | smp_mb(); |
160 | 166 | ||
161 | while (cpumask_weight(&cpus_in_crash) < ncpus) | 167 | while (atomic_read(&cpus_in_crash) < ncpus) |
162 | cpu_relax(); | 168 | cpu_relax(); |
163 | } | 169 | } |
164 | 170 | ||
@@ -316,7 +322,6 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
316 | * such that another IPI will not be sent. | 322 | * such that another IPI will not be sent. |
317 | */ | 323 | */ |
318 | crashing_cpu = smp_processor_id(); | 324 | crashing_cpu = smp_processor_id(); |
319 | crash_save_cpu(regs, crashing_cpu); | ||
320 | 325 | ||
321 | /* | 326 | /* |
322 | * If we came in via system reset, wait a while for the secondary | 327 | * If we came in via system reset, wait a while for the secondary |
@@ -326,7 +331,11 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
326 | mdelay(PRIMARY_TIMEOUT); | 331 | mdelay(PRIMARY_TIMEOUT); |
327 | 332 | ||
328 | crash_kexec_prepare_cpus(crashing_cpu); | 333 | crash_kexec_prepare_cpus(crashing_cpu); |
329 | cpumask_set_cpu(crashing_cpu, &cpus_in_crash); | 334 | |
335 | crash_save_cpu(regs, crashing_cpu); | ||
336 | |||
337 | time_to_dump = 1; | ||
338 | |||
330 | crash_kexec_wait_realmode(crashing_cpu); | 339 | crash_kexec_wait_realmode(crashing_cpu); |
331 | 340 | ||
332 | machine_kexec_mask_interrupts(); | 341 | machine_kexec_mask_interrupts(); |