void stop_this_cpu(void *dummy) { local_irq_disable(); /* * Remove this CPU: */ set_cpu_online(smp_processor_id(), false); disable_local_APIC(); mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); for (;;) halt(); }
static void native_stop_other_cpus(int wait) { unsigned long flags; unsigned long timeout; if (reboot_force) return; /* * Use an own vector here because smp_call_function * does lots of things not suitable in a panic situation. */ /* * We start by using the REBOOT_VECTOR irq. * The irq is treated as a sync point to allow critical * regions of code on other cpus to release their spin locks * and re-enable irqs. Jumping straight to an NMI might * accidentally cause deadlocks with further shutdown/panic * code. By syncing, we give the cpus up to one second to * finish their work before we force them off with the NMI. */ if (num_online_cpus() > 1) { /* did someone beat us here? */ if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1) return; /* sync above data before sending IRQ */ wmb(); apic->send_IPI_allbutself(REBOOT_VECTOR); /* * Don't wait longer than a second if the caller * didn't ask us to wait. */ timeout = USEC_PER_SEC; while (num_online_cpus() > 1 && (wait || timeout--)) udelay(1); } /* if the REBOOT_VECTOR didn't work, try with the NMI */ if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) { if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, NMI_FLAG_FIRST, "smp_stop")) /* Note: we ignore failures here */ /* Hope the REBOOT_IRQ is good enough */ goto finish; /* sync above data before sending IRQ */ wmb(); pr_emerg("Shutting down cpus with NMI\n"); apic->send_IPI_allbutself(NMI_VECTOR); /* * Don't wait longer than a 10 ms if the caller * didn't ask us to wait. */ timeout = USEC_PER_MSEC * 10; while (num_online_cpus() > 1 && (wait || timeout--)) udelay(1); } finish: local_irq_save(flags); disable_local_APIC(); mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); local_irq_restore(flags); }