[Skiboot] [RFC/WIP/PATCH v2] Fast reboot for P8

Michael Neuling mikey at neuling.org
Wed Jul 27 17:36:14 AEST 2016


On Wed, 2016-07-27 at 15:31 +1000, Michael Neuling wrote:
>> > This is an experimental patch that implements "Fast reboot" on P8
> > machines.
> >  
> > The basic idea is that when the OS calls OPAL reboot, we gather all
> > the threads in the system using a combination of patching the reset
> > vector and soft-resetting them, then cleanup a few bits of hardware
> > (we do re-probe PCIe for example), and reload & restart the bootloader.
> Awesome!!!
> 
> FWIW This is an additional patch to get it to work with 1 CPU on mambo.
 It
> works nicely if you pass in a PNOR image via bogus disk. It'll reload the
> kernel & petitboot on each reboot.

Here's a slightly better version that handles multi-core/thread.

It uses the mambo callthru to run a tcl command to send the CPUs to
0x100.

mambo confuses skiboot a bit when the topology doesn't match real
hardware (eg. when mambo configures a power8 with less than 8
threads).  So we need to fix that up at some point.

mambo also seems to have some issues with not running any instructions
on the threads when they are sent to 0x100 for many seconds. This
means the reboot takes much longer than it needs to with many threads.
We may need to reset the thread priorities to fix this.

Mikey

diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index ce6c967..df6795f 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -54,6 +54,8 @@ static int set_special_wakeup(struct cpu_thread *cpu)
 	core_id = pir_to_core_id(cpu->pir);
 
 	prlog(PR_DEBUG, "RESET Waking up core 0x%x\n", core_id);
+	if (chip_quirk(QUIRK_MAMBO_CALLOUTS))
+		return OPAL_SUCCESS;
 
 	/*
 	 * The original HWp reads the XSCOM first but ignores the result
@@ -165,6 +167,8 @@ static int clr_special_wakeup(struct cpu_thread *cpu)
 	core_id = pir_to_core_id(cpu->pir);
 
 	prlog(PR_DEBUG, "RESET: Releasing core 0x%x wakeup\n", core_id);
+	if (chip_quirk(QUIRK_MAMBO_CALLOUTS))
+		return OPAL_SUCCESS;
 
 	/*
 	 * The original HWp reads the XSCOM first but ignores the result
@@ -197,12 +201,23 @@ static int clr_special_wakeup(struct cpu_thread *cpu)
 	return 0;
 }
 
+extern unsigned long callthru_tcl(const char *str, int strlen);
+
 static void set_direct_ctl(struct cpu_thread *cpu, uint64_t bits)
 {
 	uint32_t core_id = pir_to_core_id(cpu->pir);
 	uint32_t chip_id = pir_to_chip_id(cpu->pir);
 	uint32_t thread_id = pir_to_thread_id(cpu->pir);
 	uint32_t xscom_addr;
+	char tcl_cmd[50];
+
+	if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) {
+		if (bits != P8_DIRECT_CTL_SRESET)
+			return;
+		snprintf(tcl_cmd, 50, "mysim cpu %i:%i set spr pc 0x100", core_id, thread_id);
+		callthru_tcl(tcl_cmd, strlen(tcl_cmd));
+		return;
+	}
 
 	xscom_addr = XSCOM_ADDR_P8_EX(core_id,
 				      P8_EX_TCTL_DIRECT_CONTROLS(thread_id));
@@ -301,10 +316,14 @@ void fast_reboot(void)
 	/* Unlock, at this point we go away */
 	unlock(&reset_lock);
 
-	if (success)
+	if (success) {
+		if (!next_cpu(first_cpu()))
+			/*  Only 1 CPU, so fake a reset of myself */
+			asm volatile("ba 0x100 " : : : );
 		/* Don't return */
 		for (;;)
 			;
+	}
 }
 
 static void cleanup_cpu_state(void)
@@ -404,12 +423,12 @@ void __noreturn fast_reboot_entry(void)
 	time_wait_ms(100);
 
 	lock(&reset_lock);
-	if (last_man_standing) {
+	if (last_man_standing && next_cpu(first_cpu())) {
 		prlog(PR_DEBUG, "RESET: last man standing fixup...\n");
 		set_direct_ctl(last_man_standing, P8_DIRECT_CTL_PRENAP);
 		set_direct_ctl(last_man_standing, P8_DIRECT_CTL_SRESET);
-		last_man_standing = NULL;
 	}
+	last_man_standing = NULL;
 	unlock(&reset_lock);
 
 	/* We reset our ICP first ! Otherwise we might get stray interrupts
diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
index 066f748..caa94f6 100644
--- a/platforms/mambo/mambo.c
+++ b/platforms/mambo/mambo.c
@@ -92,6 +92,8 @@ static inline int callthru3(int command, unsigned long arg1, unsigned long arg2,
 #define BOGUS_DISK_WRITE	117
 #define BOGUS_DISK_INFO		118
 
+#define CALL_TCL		86
+
 static inline int callthru_disk_read(int id, void *buf, unsigned long sect,
 				     unsigned long nrsect)
 {
@@ -112,6 +114,15 @@ static inline unsigned long callthru_disk_info(int op, int id)
 			 (unsigned long)id);
 }
 
+extern unsigned long callthru_tcl(const char *str, int strlen);
+
+unsigned long callthru_tcl(const char *str, int strlen)
+{
+	prlog(PR_DEBUG, "Sending TCL cmd: %s\n", str);
+	return callthru2(CALL_TCL, (unsigned long)str,
+			 (unsigned long)strlen);
+}
+
 struct bogus_disk_info {
 	unsigned long size;
 	int id;


More information about the Skiboot mailing list