|
@@ -374,9 +374,55 @@ static void mpc85xx_smp_kexec_down(void *arg)
|
|
|
#else
|
|
|
void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
|
|
|
{
|
|
|
+ int cpu = smp_processor_id();
|
|
|
+ int sibling = cpu_last_thread_sibling(cpu);
|
|
|
+ bool notified = false;
|
|
|
+ int disable_cpu;
|
|
|
+ int disable_threadbit = 0;
|
|
|
+ long start = mftb();
|
|
|
+ long now;
|
|
|
+
|
|
|
local_irq_disable();
|
|
|
hard_irq_disable();
|
|
|
mpic_teardown_this_cpu(secondary);
|
|
|
+
|
|
|
+ if (cpu == crashing_cpu && cpu_thread_in_core(cpu) != 0) {
|
|
|
+ /*
|
|
|
+ * We enter the crash kernel on whatever cpu crashed,
|
|
|
+ * even if it's a secondary thread. If that's the case,
|
|
|
+ * disable the corresponding primary thread.
|
|
|
+ */
|
|
|
+ disable_threadbit = 1;
|
|
|
+ disable_cpu = cpu_first_thread_sibling(cpu);
|
|
|
+ } else if (sibling != crashing_cpu &&
|
|
|
+ cpu_thread_in_core(cpu) == 0 &&
|
|
|
+ cpu_thread_in_core(sibling) != 0) {
|
|
|
+ disable_threadbit = 2;
|
|
|
+ disable_cpu = sibling;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (disable_threadbit) {
|
|
|
+ while (paca[disable_cpu].kexec_state < KEXEC_STATE_REAL_MODE) {
|
|
|
+ barrier();
|
|
|
+ now = mftb();
|
|
|
+ if (!notified && now - start > 1000000) {
|
|
|
+ pr_info("%s/%d: waiting for cpu %d to enter KEXEC_STATE_REAL_MODE (%d)\n",
|
|
|
+ __func__, smp_processor_id(),
|
|
|
+ disable_cpu,
|
|
|
+ paca[disable_cpu].kexec_state);
|
|
|
+ notified = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (notified) {
|
|
|
+ pr_info("%s: cpu %d done waiting\n",
|
|
|
+ __func__, disable_cpu);
|
|
|
+ }
|
|
|
+
|
|
|
+ mtspr(SPRN_TENC, disable_threadbit);
|
|
|
+ while (mfspr(SPRN_TENSR) & disable_threadbit)
|
|
|
+ cpu_relax();
|
|
|
+ }
|
|
|
}
|
|
|
#endif
|
|
|
|