diff mbox series

[RFC] fast-reboot: implement fast reboot for p9

Message ID 20171124201536.25007-1-npiggin@gmail.com
State Superseded
Headers show
Series [RFC] fast-reboot: implement fast reboot for p9 | expand

Commit Message

Nicholas Piggin Nov. 24, 2017, 8:15 p.m. UTC
This is a really quick hack that still needs some cleanups and more
testing, but it's survived a few fast reboots so far (this goes on
top of the fast reboot series and the bitmap corruption fix).

... Actually it seems like it's locks up some time after the second
reboot now. It apparently got further without that bitmap iteration
fix. Anyway it's late I'll just post this out for now.

---
 core/direct-controls.c |  7 ++---
 core/fast-reboot.c     | 72 ++++++++++++++++++++++++++++----------------------
 core/init.c            | 21 +++++++++------
 hw/xive.c              | 23 +++++++++++-----
 include/xive.h         |  1 +
 5 files changed, 75 insertions(+), 49 deletions(-)
diff mbox series

Patch

diff --git a/core/direct-controls.c b/core/direct-controls.c
index ed105b81c..56e85b295 100644
--- a/core/direct-controls.c
+++ b/core/direct-controls.c
@@ -270,7 +270,7 @@  static int p8_sreset_thread(struct cpu_thread *cpu)
 
 /* Waking may take up to 5ms for deepest sleep states. Set timeout to 100ms */
 #define P9_SPWKUP_POLL_INTERVAL		100
-#define P9_SPWKUP_TIMEOUT		100000
+#define P9_SPWKUP_TIMEOUT		1000000
 
 /*
  * This implements direct control facilities of processor cores and threads
@@ -304,7 +304,7 @@  static int p9_core_set_special_wakeup(struct cpu_thread *cpu)
 			goto out_fail;
 		}
 		if (val & P9_SPECIAL_WKUP_DONE)
-			return 0;
+			return OPAL_SUCCESS;
 
 		time_wait_us(P9_SPWKUP_POLL_INTERVAL);
 	}
@@ -312,6 +312,7 @@  static int p9_core_set_special_wakeup(struct cpu_thread *cpu)
 	prlog(PR_ERR, "Could not set special wakeup on %u:%u:"
 			" timeout waiting for SPECIAL_WKUP_DONE.\n",
 			chip_id, core_id);
+	return OPAL_SUCCESS;
 
 out_fail:
 	/* De-assert special wakeup after a small delay. */
@@ -355,7 +356,7 @@  static int p9_core_clear_special_wakeup(struct cpu_thread *cpu)
 			return OPAL_HARDWARE;
 		}
 		if (!(val & P9_SPECIAL_WKUP_DONE))
-			return 0;
+			return OPAL_SUCCESS;
 
 		time_wait_us(P9_SPWKUP_POLL_INTERVAL);
 	}
diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index 350ccd375..4faf6dd08 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -24,6 +24,7 @@ 
 #include <cec.h>
 #include <timebase.h>
 #include <pci.h>
+#include <xive.h>
 #include <chip.h>
 #include <chiptod.h>
 #include <ipmi.h>
@@ -61,9 +62,6 @@  static bool cpu_state_wait_all_others(enum cpu_thread_state state,
 	return true;
 }
 
-extern void *fdt;
-extern struct lock capi_lock;
-
 static const char *fast_reboot_disabled = NULL;
 
 void disable_fast_reboot(const char *reason)
@@ -77,7 +75,7 @@  void fast_reboot(void)
 	static int fast_reboot_count = 0;
 
 	if (chip_quirk(QUIRK_MAMBO_CALLOUTS) ||
-			proc_gen != proc_gen_p8) {
+			(proc_gen != proc_gen_p8 && proc_gen != proc_gen_p9)) {
 		prlog(PR_DEBUG,
 		      "RESET: Fast reboot not available on this CPU\n");
 		return;
@@ -104,10 +102,9 @@  void fast_reboot(void)
 		return;
 	}
 
-	prlog(PR_NOTICE, "RESET: Initiating fast reboot %d...\n", ++fast_reboot_count);
-
-	free(fdt);
+	/* Should mem_check() all regions before allowing fast reboot */
 
+	prlog(PR_NOTICE, "RESET: Initiating fast reboot %d...\n", ++fast_reboot_count);
 	fast_boot_release = false;
 	sync();
 
@@ -172,13 +169,15 @@  static void cleanup_cpu_state(void)
 		/* XXX Update the SLW copies ! Also dbl check HIDs etc... */
 		init_shared_sprs();
 
-		/* If somebody was in fast_sleep, we may have a workaround
-		 * to undo
-		 */
-		if (cpu->in_fast_sleep) {
-			prlog(PR_DEBUG, "RESET: CPU 0x%04x in fast sleep"
-			      " undoing workarounds...\n", cpu->pir);
-			fast_sleep_exit();
+		if (proc_gen == proc_gen_p8) {
+			/* If somebody was in fast_sleep, we may have a
+			 * workaround to undo
+			 */
+			if (cpu->in_fast_sleep) {
+				prlog(PR_DEBUG, "RESET: CPU 0x%04x in fast sleep"
+				      " undoing workarounds...\n", cpu->pir);
+				fast_sleep_exit();
+			}
 		}
 
 		/* And we might have lost TB sync */
@@ -252,15 +251,17 @@  void __noreturn fast_reboot_entry(void)
 {
 	prlog(PR_DEBUG, "RESET: CPU 0x%04x reset in\n", this_cpu()->pir);
 
-	/* We reset our ICP first ! Otherwise we might get stray interrupts
-	 * when unsplitting
-	 */
-	reset_cpu_icp();
+	if (proc_gen == proc_gen_p8) {
+		/* We reset our ICP first ! Otherwise we might get stray
+		 * interrupts when unsplitting
+		 */
+		reset_cpu_icp();
 
-	/* If we are split, we need to unsplit. Since that can send us
-	 * to NAP, which will come back via reset, we do it now
-	 */
-	check_split_core();
+		/* If we are split, we need to unsplit. Since that can send us
+		 * to NAP, which will come back via reset, we do it now
+		 */
+		check_split_core();
+	}
 
 	sync();
 	this_cpu()->state = cpu_state_present;
@@ -295,6 +296,14 @@  void __noreturn fast_reboot_entry(void)
 	sync();
 	fast_boot_release = true;
 
+	/* Cleanup ourselves */
+	cleanup_cpu_state();
+
+	/* Set our state to active */
+	sync();
+	this_cpu()->state = cpu_state_active;
+	sync();
+
 	/* Wait for them to respond */
 	cpu_state_wait_all_others(cpu_state_active, 0);
 
@@ -305,14 +314,6 @@  void __noreturn fast_reboot_entry(void)
 	/* Clear release flag for next time */
 	fast_boot_release = false;
 
-	/* Cleanup ourselves */
-	cleanup_cpu_state();
-
-	/* Set our state to active */
-	sync();
-	this_cpu()->state = cpu_state_active;
-	sync();
-
 	/* Let the CPU layer do some last minute global cleanups */
 	cpu_fast_reboot_complete();
 
@@ -326,8 +327,15 @@  void __noreturn fast_reboot_entry(void)
 	/* Poke the consoles (see comments in the code there) */
 	fsp_console_reset();
 
-	/* Reset/EOI the PSI interrupt */
-	psi_irq_reset();
+	if (proc_gen == proc_gen_p8) {
+		/* XXX */
+		/* Reset/EOI the PSI interrupt */
+		psi_irq_reset();
+	}
+
+	if (proc_gen == proc_gen_p9) {
+		xive_reset();
+	}
 
 	/* Remove all PCI devices */
 	pci_reset();
diff --git a/core/init.c b/core/init.c
index 89a275812..c7f45eed5 100644
--- a/core/init.c
+++ b/core/init.c
@@ -501,18 +501,23 @@  void __noreturn load_and_boot_kernel(bool is_reboot)
 
 		/* Wait for FW VPD data read to complete */
 		fsp_code_update_wait_vpd(true);
-	} else
+
+		/*
+		 * OCC takes few secs to boot.  Call this as late as
+		 * as possible to avoid delay.
+		 */
+		occ_pstates_init();
+		occ_sensors_init();
+	} else {
+		/* fdt will be rebuilt */
+		free(fdt);
+		fdt = NULL;
+
 		nvram_reinit();
+	}
 
 	fsp_console_select_stdout();
 
-	/*
-	 * OCC takes few secs to boot.  Call this as late as
-	 * as possible to avoid delay.
-	 */
-	occ_pstates_init();
-	occ_sensors_init();
-
 	/* Use nvram bootargs over device tree */
 	cmdline = nvram_query("bootargs");
 	if (cmdline) {
diff --git a/hw/xive.c b/hw/xive.c
index df38074de..17e3744cf 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -4431,15 +4431,10 @@  static void xive_reset_mask_source_cb(struct irq_source *is,
 	}
 }
 
-static int64_t opal_xive_reset(uint64_t version)
+static int64_t __xive_reset(uint64_t version)
 {
 	struct proc_chip *chip;
 
-	prlog(PR_DEBUG, "XIVE reset, version: %d...\n", (int)version);
-
-	if (version > 1)
-		return OPAL_PARAMETER;
-
 	xive_mode = version;
 
 	/* Mask all interrupt sources */
@@ -4474,6 +4469,22 @@  static int64_t opal_xive_reset(uint64_t version)
 	return OPAL_SUCCESS;
 }
 
+/* Called by fast reboot */
+int64_t xive_reset(void)
+{
+	return __xive_reset(XIVE_MODE_EMU);
+}
+
+static int64_t opal_xive_reset(uint64_t version)
+{
+	prlog(PR_DEBUG, "XIVE reset, version: %d...\n", (int)version);
+
+	if (version > 1)
+		return OPAL_PARAMETER;
+
+	return __xive_reset(version);
+}
+
 static int64_t opal_xive_free_vp_block(uint64_t vp_base)
 {
 	uint32_t blk, idx, i, count;
diff --git a/include/xive.h b/include/xive.h
index 63ee77b38..8c65f4750 100644
--- a/include/xive.h
+++ b/include/xive.h
@@ -469,6 +469,7 @@  struct xive_vp {
 #define XIVE_IRQ_ERROR	0xffffffff
 
 void init_xive(void);
+int64_t xive_reset(void);
 
 /* Allocate a chunk of HW sources */
 uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align);