X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fkernel%2Fcrash.c;fp=arch%2Fpowerpc%2Fkernel%2Fcrash.c;h=778f22fd85d2e96eab7e3e84ed19ac0f25fb3765;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=1af41f7616dc84b280f60832ae7e2e9a9d5378bf;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 1af41f761..778f22fd8 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -22,13 +22,10 @@ #include #include #include -#include #include -#include #include #include -#include #include #include #include @@ -43,8 +40,6 @@ /* This keeps a track of which one is crashing cpu. */ int crashing_cpu = -1; -static cpumask_t cpus_in_crash = CPU_MASK_NONE; -cpumask_t cpus_in_sr = CPU_MASK_NONE; static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, size_t data_len) @@ -102,72 +97,34 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu) } #ifdef CONFIG_SMP -static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); +static atomic_t waiting_for_crash_ipi; void crash_ipi_callback(struct pt_regs *regs) { int cpu = smp_processor_id(); - if (!cpu_online(cpu)) + if (cpu == crashing_cpu) return; - local_irq_disable(); - if (!cpu_isset(cpu, cpus_in_crash)) - crash_save_this_cpu(regs, cpu); - cpu_set(cpu, cpus_in_crash); - - /* - * Entered via soft-reset - could be the kdump - * process is invoked using soft-reset or user activated - * it if some CPU did not respond to an IPI. - * For soft-reset, the secondary CPU can enter this func - * twice. 1 - using IPI, and 2. soft-reset. - * Tell the kexec CPU that entered via soft-reset and ready - * to go down. - */ - if (cpu_isset(cpu, cpus_in_sr)) { - cpu_clear(cpu, cpus_in_sr); - atomic_inc(&enter_on_soft_reset); - } - - /* - * Starting the kdump boot. - * This barrier is needed to make sure that all CPUs are stopped. - * If not, soft-reset will be invoked to bring other CPUs. - */ - while (!cpu_isset(crashing_cpu, cpus_in_crash)) - cpu_relax(); + if (!cpu_online(cpu)) + return; if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 1); -#ifdef CONFIG_PPC64 - kexec_smp_wait(); -#else - for (;;); /* FIXME */ -#endif + local_irq_disable(); + crash_save_this_cpu(regs, cpu); + atomic_dec(&waiting_for_crash_ipi); + kexec_smp_wait(); /* NOTREACHED */ } -/* - * Wait until all CPUs are entered via soft-reset. - */ -static void crash_soft_reset_check(int cpu) -{ - unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ - - cpu_clear(cpu, cpus_in_sr); - while (atomic_read(&enter_on_soft_reset) != ncpus) - cpu_relax(); -} - - -static void crash_kexec_prepare_cpus(int cpu) +static void crash_kexec_prepare_cpus(void) { unsigned int msecs; - unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); crash_send_ipi(crash_ipi_callback); smp_wmb(); @@ -175,13 +132,14 @@ static void crash_kexec_prepare_cpus(int cpu) /* * FIXME: Until we will have the way to stop other CPUSs reliabally, * the crash CPU will send an IPI and wait for other CPUs to - * respond. + * respond. If not, proceed the kexec boot even though we failed to + * capture other CPU states. * Delay of at least 10 seconds. */ - printk(KERN_EMERG "Sending IPI to other cpus...\n"); + printk(KERN_ALERT "Sending IPI to other cpus...\n"); msecs = 10000; - while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { - cpu_relax(); + while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) { + barrier(); mdelay(1); } @@ -190,71 +148,18 @@ static void crash_kexec_prepare_cpus(int cpu) /* * FIXME: In case if we do not get all CPUs, one possibility: ask the * user to do soft reset such that we get all. - * Soft-reset will be used until better mechanism is implemented. + * IPI handler is already set by the panic cpu initially. Therefore, + * all cpus could invoke this handler from die() and the panic CPU + * will call machine_kexec() directly from this handler to do + * kexec boot. */ - if (cpus_weight(cpus_in_crash) < ncpus) { - printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n", - ncpus - cpus_weight(cpus_in_crash)); - printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n"); - cpus_in_sr = CPU_MASK_NONE; - atomic_set(&enter_on_soft_reset, 0); - while (cpus_weight(cpus_in_crash) < ncpus) - cpu_relax(); - } - /* - * Make sure all CPUs are entered via soft-reset if the kdump is - * invoked using soft-reset. - */ - if (cpu_isset(cpu, cpus_in_sr)) - crash_soft_reset_check(cpu); + if (atomic_read(&waiting_for_crash_ipi)) + printk(KERN_ALERT "done waiting: %d cpus not responding\n", + atomic_read(&waiting_for_crash_ipi)); /* Leave the IPI callback set */ } - -/* - * This function will be called by secondary cpus or by kexec cpu - * if soft-reset is activated to stop some CPUs. - */ -void crash_kexec_secondary(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - unsigned long flags; - int msecs = 5; - - local_irq_save(flags); - /* Wait 5ms if the kexec CPU is not entered yet. */ - while (crashing_cpu < 0) { - if (--msecs < 0) { - /* - * Either kdump image is not loaded or - * kdump process is not started - Probably xmon - * exited using 'x'(exit and recover) or - * kexec_should_crash() failed for all running tasks. - */ - cpu_clear(cpu, cpus_in_sr); - local_irq_restore(flags); - return; - } - mdelay(1); - cpu_relax(); - } - if (cpu == crashing_cpu) { - /* - * Panic CPU will enter this func only via soft-reset. - * Wait until all secondary CPUs entered and - * then start kexec boot. - */ - crash_soft_reset_check(cpu); - cpu_set(crashing_cpu, cpus_in_crash); - if (ppc_md.kexec_cpu_down) - ppc_md.kexec_cpu_down(1, 0); - machine_kexec(kexec_crash_image); - /* NOTREACHED */ - } - crash_ipi_callback(regs); -} - #else -static void crash_kexec_prepare_cpus(int cpu) +static void crash_kexec_prepare_cpus(void) { /* * move the secondarys to us so that we can copy @@ -262,26 +167,16 @@ static void crash_kexec_prepare_cpus(int cpu) * * do this if kexec in setup.c ? */ -#ifdef CONFIG_PPC64 smp_release_cpus(); -#else - /* FIXME */ -#endif } -void crash_kexec_secondary(struct pt_regs *regs) -{ - cpus_in_sr = CPU_MASK_NONE; -} #endif void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; - /* * This function is only called after the system - * has panicked or is otherwise in a critical state. + * has paniced or is otherwise in a critical state. * The minimum amount of code to allow a kexec'd kernel * to run successfully needs to happen here. * @@ -291,24 +186,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ local_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; - - if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); - - if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); - } + if (ppc_md.kexec_cpu_down) + ppc_md.kexec_cpu_down(1, 0); /* * Make a note of crashing cpu. Will be used in machine_kexec * such that another IPI will not be sent. */ crashing_cpu = smp_processor_id(); + crash_kexec_prepare_cpus(); crash_save_this_cpu(regs, crashing_cpu); - crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); - if (ppc_md.kexec_cpu_down) - ppc_md.kexec_cpu_down(1, 0); }