diff mbox series

[v2] WIP: POWER8 SRESET

Message ID 20190307054334.3088-1-alistair@popple.id.au
State Superseded
Headers show
Series [v2] WIP: POWER8 SRESET | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (deb577949a3505064f471e7b7c692e37c38ec8a4)
snowpatch_ozlabs/build-multiarch success Test build-multiarch on branch master

Commit Message

Alistair Popple March 7, 2019, 5:43 a.m. UTC
SRESET on POWER8 is made more complex because it can only be run if a
thread is in a powersave state. This makes getting an active thread
into SRESET hard because we need to emulate what the processor does
using instruction ramming.

This patch aims to implement this sequence. If a thread is in a nap
state it will just use the direct controls, however if it is in an
active state it will quiesce the thread and use instruction ramming to
put the thread at the 0x100 sreset exception vector.

Signed-off-by: Alistair Popple <alistair@popple.id.au>
---
 libpdbg/chip.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 libpdbg/p8chip.c | 24 ++++++++++++++++++------
 src/thread.c     | 14 ++++++++++++++
 3 files changed, 74 insertions(+), 6 deletions(-)

Comments

Artem Senichev March 7, 2019, 8:58 a.m. UTC | #1
On Thu, Mar 07, 2019 at 04:43:34PM +1100, Alistair Popple wrote:
> SRESET on POWER8 is made more complex because it can only be run if a
> thread is in a powersave state. This makes getting an active thread
> into SRESET hard because we need to emulate what the processor does
> using instruction ramming.
> 
> This patch aims to implement this sequence. If a thread is in a nap
> state it will just use the direct controls, however if it is in an
> active state it will quiesce the thread and use instruction ramming to
> put the thread at the 0x100 sreset exception vector.
> 
> Signed-off-by: Alistair Popple <alistair@popple.id.au>
> ---
>  libpdbg/chip.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
>  libpdbg/p8chip.c | 24 ++++++++++++++++++------
>  src/thread.c     | 14 ++++++++++++++
>  3 files changed, 74 insertions(+), 6 deletions(-)

Hi Alistair,
I've tried the patch, just out of curiosity, it looks like two
simultaneous sreset signal are send to the host, the kernel hangs with
message:

cpu 0x0: Vector: 100 (System Reset) at [c000000001d07bb8]
    pc: c0000000000a84d8: power7_idle_type+0x68/0x90
    lr: c0000000000a84d8: power7_idle_type+0x68/0x90
    sp: c000000001d07d30
   msr: 9000000000001033
  current = 0xc000000001cb1900
  paca    = 0xc000000001f70000	 irqmask: 0x03	 irq_happened: 0x01
    pid   = 0, comm = swapper/0
Linux version 5.0.0 (art@art) (gcc version 8.3.0 (Buildroot 2019.05-git-01359-g9550765adb)) #2 SMP Thu Mar 7 10:39:05 MSK 2019
cpu 0x80: Vector: 100 (System Reset) at [c000003fcadb3bd8]
    pc: c0000000000a84d8: power7_idle_type+0x68/0x90
    lr: c0000000000a84d8: power7_idle_type+0x68/0x90
    sp: c000003fcadb3d50
   msr: 9000000000001033
  current = 0xc000003fcad45600
  paca    = 0xc000003fff6db880	 irqmask: 0x03	 irq_happened: 0x01
    pid   = 0, comm = swapper/128
Linux version 5.0.0 (art@art) (gcc version 8.3.0 (Buildroot 2019.05-git-01359-g9550765adb)) #2 SMP Thu Mar 7 10:39:05 MSK 2019

It happens when the target CPU thread is idle, with 100% loading there
is still 'cpu 0x0: Vector: 400 (Instruction Access)' error.
Stewart Smith March 7, 2019, 8:49 p.m. UTC | #2
Alistair Popple <alistair@popple.id.au> writes:
> SRESET on POWER8 is made more complex because it can only be run if a
> thread is in a powersave state. This makes getting an active thread
> into SRESET hard because we need to emulate what the processor does
> using instruction ramming.

The pure SRESET part can also be had with fast-reboot, see
https://github.com/open-power/op-test-framework/pull/437 for pretty
reproducible test case (I upped to 120 seconds most recently, and that
hits it within a couple of iterations pretty reliably).

Next up for today is to resurrect the instruction ramming in skiboot and
see if I make things better there.

Looks like we have exactly the same problem in two places :)
Alistair Popple March 8, 2019, 4:39 a.m. UTC | #3
Thanks for testing Artem, although as you point out this was a very work in 
progress patch and wasn't really complete/tested. However Nick's just posted a 
series with a heap of bugfixes and it seems to work much more reliably on my 
system at least so it would be worth giving that a shot.

Regards,

Alistair

On Thursday, 7 March 2019 11:58:48 AM AEDT Artem Senichev wrote:
> On Thu, Mar 07, 2019 at 04:43:34PM +1100, Alistair Popple wrote:
> > SRESET on POWER8 is made more complex because it can only be run if a
> > thread is in a powersave state. This makes getting an active thread
> > into SRESET hard because we need to emulate what the processor does
> > using instruction ramming.
> > 
> > This patch aims to implement this sequence. If a thread is in a nap
> > state it will just use the direct controls, however if it is in an
> > active state it will quiesce the thread and use instruction ramming to
> > put the thread at the 0x100 sreset exception vector.
> > 
> > Signed-off-by: Alistair Popple <alistair@popple.id.au>
> > ---
> > 
> >  libpdbg/chip.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
> >  libpdbg/p8chip.c | 24 ++++++++++++++++++------
> >  src/thread.c     | 14 ++++++++++++++
> >  3 files changed, 74 insertions(+), 6 deletions(-)
> 
> Hi Alistair,
> I've tried the patch, just out of curiosity, it looks like two
> simultaneous sreset signal are send to the host, the kernel hangs with
> message:
> 
> cpu 0x0: Vector: 100 (System Reset) at [c000000001d07bb8]
>     pc: c0000000000a84d8: power7_idle_type+0x68/0x90
>     lr: c0000000000a84d8: power7_idle_type+0x68/0x90
>     sp: c000000001d07d30
>    msr: 9000000000001033
>   current = 0xc000000001cb1900
>   paca    = 0xc000000001f70000	 irqmask: 0x03	 irq_happened: 0x01
>     pid   = 0, comm = swapper/0
> Linux version 5.0.0 (art@art) (gcc version 8.3.0 (Buildroot
> 2019.05-git-01359-g9550765adb)) #2 SMP Thu Mar 7 10:39:05 MSK 2019 cpu
> 0x80: Vector: 100 (System Reset) at [c000003fcadb3bd8]
>     pc: c0000000000a84d8: power7_idle_type+0x68/0x90
>     lr: c0000000000a84d8: power7_idle_type+0x68/0x90
>     sp: c000003fcadb3d50
>    msr: 9000000000001033
>   current = 0xc000003fcad45600
>   paca    = 0xc000003fff6db880	 irqmask: 0x03	 irq_happened: 0x01
>     pid   = 0, comm = swapper/128
> Linux version 5.0.0 (art@art) (gcc version 8.3.0 (Buildroot
> 2019.05-git-01359-g9550765adb)) #2 SMP Thu Mar 7 10:39:05 MSK 2019
> 
> It happens when the target CPU thread is idle, with 100% loading there
> is still 'cpu 0x0: Vector: 400 (Instruction Access)' error.
diff mbox series

Patch

diff --git a/libpdbg/chip.c b/libpdbg/chip.c
index 5b67c7b..da412d5 100644
--- a/libpdbg/chip.c
+++ b/libpdbg/chip.c
@@ -534,3 +534,45 @@  int ram_state_thread(struct pdbg_target *thread, struct thread_regs *regs)
 
 	return 0;
 }
+
+#define SPR_SRR0 0x01a
+#define SPR_SRR1 0x01b
+
+#define MSR_HV          PPC_BIT(3)      /* Hypervisor mode */
+#define MSR_EE          PPC_BIT(48)     /* External Int. Enable */
+#define MSR_FE0         PPC_BIT(52)     /* FP Exception 0 */
+#define MSR_FE1         PPC_BIT(55)     /* FP Exception 1 */
+#define MSR_IR          PPC_BIT(58)     /* Instructions reloc */
+#define MSR_DR          PPC_BIT(59)     /* Data reloc */
+#define MSR_RI          PPC_BIT(62)     /* Recoverable Interrupt */
+
+int emulate_sreset(struct thread *thread)
+{
+	uint64_t opcodes[] = {
+		mfmsr(0), mtspr(277, 0),		/* Get MSR */
+		mfnia(0), mtspr(277, 0),		/* Get NIA */
+		mfspr(0, 277), mtmsr(0),		/* Put modified MSR back */
+		mfspr(0, 277), mtspr(SPR_SRR0, 0),	/* Set SRR0 to NIA */
+		mfspr(0, 277), mtspr(SPR_SRR1, 0),	/* Set SRR1 to SRESET value */
+		mfspr(0, 277), mtnia(0),		/* Set NIA */
+	};
+	uint64_t results[] = {
+		0, 0,
+		0, 0,
+		0, 0,
+		0, 0,					/* SRR0 */
+		0, 0,			      		/* SRR1 SRESET value */
+		0x100, 0,				/* Set NIA = 0x100 */
+	};
+
+	/* RAM first 4 opcodes */
+	CHECK_ERR(ram_instructions(&thread->target, opcodes, results, 4, 0));
+
+	/* Set MSR, SRR0 = NIA and ram remaining instructions*/
+	results[4] = (results[1] & ~(MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE | MSR_RI)) | MSR_HV;
+	results[6] = results[3];
+	results[8] = results[1];
+	CHECK_ERR(ram_instructions(&thread->target, &opcodes[4], &results[4], ARRAY_SIZE(opcodes) - 4, 0));
+
+	return 0;
+}
diff --git a/libpdbg/p8chip.c b/libpdbg/p8chip.c
index 914c335..50fef5f 100644
--- a/libpdbg/p8chip.c
+++ b/libpdbg/p8chip.c
@@ -29,6 +29,8 @@ 
 #define RAS_STATUS_TIMEOUT	100
 
 #define DIRECT_CONTROLS_REG    		0x0
+#define  DIRECT_CONTROL_PRENAP		PPC_BIT(47)
+#define  DIRECT_CONTROL_SRESET		PPC_BIT(60)
 #define  DIRECT_CONTROL_SP_STEP		PPC_BIT(61)
 #define  DIRECT_CONTROL_SP_START 	PPC_BIT(62)
 #define  DIRECT_CONTROL_SP_STOP 	PPC_BIT(63)
@@ -337,12 +339,6 @@  static int p8_thread_start(struct thread *thread)
 	return 0;
 }
 
-static int p8_thread_sreset(struct thread *thread)
-{
-	/* Broken on p8 */
-	return 1;
-}
-
 static int p8_ram_setup(struct thread *thread)
 {
 	struct pdbg_target *target;
@@ -440,6 +436,22 @@  static int p8_ram_destroy(struct thread *thread)
 	return 0;
 }
 
+int emulate_sreset(struct thread *thread);
+static int p8_thread_sreset(struct thread *thread)
+{
+	if (!p8_ram_setup(thread)) {
+		/* Thread was active, emulate the sreset */
+		emulate_sreset(thread);
+		p8_ram_destroy(thread);
+	} else {
+		/* Use direct controls */
+		CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_PRENAP));
+		CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SRESET));
+	}
+
+	return 0;
+}
+
 static int p8_ram_getxer(struct pdbg_target *thread, uint64_t *value)
 {
 	uint64_t opcodes[] = {mfxerf(0, 0), mtspr(277, 0), mfxerf(0, 1),
diff --git a/src/thread.c b/src/thread.c
index 1fd448d..f6a19b9 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -296,10 +296,24 @@  static int thread_sreset(void)
 		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
 			continue;
 
+		ram_stop_thread(target);
+	}
+
+	for_each_path_target_class("thread", target) {
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
+
 		ram_sreset_thread(target);
 		count++;
 	}
 
+	for_each_path_target_class("thread", target) {
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
+
+		ram_start_thread(target);
+	}
+
 	return count;
 }
 OPTCMD_DEFINE_CMD(sreset, thread_sreset);