diff mbox

[V3,2/2] powerpc/kexec: Reset HILE before entering target kernel

Message ID 1436505599-32109-3-git-send-email-sam.mj@au1.ibm.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Sam Mendoza-Jonas July 10, 2015, 5:19 a.m. UTC
On powernv secondary cpus are returned to OPAL, and will then enter the
target kernel in big-endian. However if it is set the HILE bit will persist,
causing the first exception in the target kernel to be delivered in
litte-endian regardless of the current endianess.

If running on top of OPAL make sure the HILE bit is reset before any
thread branches into the target kernel.

Signed-off-by: Samuel Mendoza-Jonas <sam.mj@au1.ibm.com>
---
 arch/powerpc/kernel/machine_kexec_64.c |  6 ++++--
 arch/powerpc/kernel/misc_64.S          | 19 +++++++++++++++++--
 2 files changed, 21 insertions(+), 4 deletions(-)

Comments

Benjamin Herrenschmidt July 17, 2015, 1:53 a.m. UTC | #1
On Fri, 2015-07-10 at 15:19 +1000, Samuel Mendoza-Jonas wrote:
> +#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_POWERNV)
> +       li      r3,(FW_FEATURE_OPAL >> 16)
> +       rldicr  r3,r3,16,63
> +       and.    r3,r3,r26
> +       cmpwi   r3,0
> +       beq     99f

If FW_FEATRURE_OPAL is 0x80000000 then the li will sign extend.

The rldicr has a mask of all F's so it will keep all the bits you
don't care about.

So together, you'll get compares happening on bits above the 16 you care
about that might change the result of your comparison incorrectly.

Since FW_FEATURE_* bits aren't ABI, they can change, so we don't want
to impose a constraint on them.

Thus I would recommend using an rdlicl r3,r3,16,48 (aka srdi r3,r3,48)
instead which is going to clear all bits above 0xffff.

Now, that being said, FW_FEATURE_* can be 64-bit and this isn't perf
critical so why not just load the full 64-bit constant into r3 and
be done with it ? There's a macro to do that:

	LOAD_REG_IMMEDIATE(r3,FW_FEATURE_OPAL)

Cheers,
Ben.
Benjamin Herrenschmidt July 17, 2015, 3:34 a.m. UTC | #2
On Fri, 2015-07-17 at 11:53 +1000, Benjamin Herrenschmidt wrote:
> On Fri, 2015-07-10 at 15:19 +1000, Samuel Mendoza-Jonas wrote:
> > +#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_POWERNV)
> > +       li      r3,(FW_FEATURE_OPAL >> 16)
> > +       rldicr  r3,r3,16,63
> > +       and.    r3,r3,r26
> > +       cmpwi   r3,0
> > +       beq     99f
> 
> If FW_FEATRURE_OPAL is 0x80000000 then the li will sign extend.
> 
> The rldicr has a mask of all F's so it will keep all the bits you
> don't care about.

../..

Even better, you should be able to just do it all in C in
pnv_kexec_cpu_down(), after we wait for secondaries to
be in OPAL. At that point interrupts are already off, so
it should be all good.
Segher Boessenkool July 17, 2015, 9:59 a.m. UTC | #3
On Fri, Jul 17, 2015 at 11:53:38AM +1000, Benjamin Herrenschmidt wrote:
> On Fri, 2015-07-10 at 15:19 +1000, Samuel Mendoza-Jonas wrote:
> > +#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_POWERNV)
> > +       li      r3,(FW_FEATURE_OPAL >> 16)
> > +       rldicr  r3,r3,16,63
> > +       and.    r3,r3,r26
> > +       cmpwi   r3,0
> > +       beq     99f
> 
> If FW_FEATRURE_OPAL is 0x80000000 then the li will sign extend.
> 
> The rldicr has a mask of all F's so it will keep all the bits you
> don't care about.
> 
> So together, you'll get compares happening on bits above the 16 you care
> about that might change the result of your comparison incorrectly.
> 
> Since FW_FEATURE_* bits aren't ABI, they can change, so we don't want
> to impose a constraint on them.
> 
> Thus I would recommend using an rdlicl r3,r3,16,48 (aka srdi r3,r3,48)
> instead which is going to clear all bits above 0xffff.

Or the other way around: instead of loading and masking, load zero and
OR the bits in:

+       li      r3,0
+       ori     r3,(FW_FEATURE_OPAL >> 16)
+       rldicr  r3,r3,16,63
+       and.    r3,r3,r26
+       cmpwi   r3,0
+       beq     99f

which of course is better written as

+       li      r3,0
+       oris    r3,(FW_FEATURE_OPAL >> 16)
+       and.    r3,r3,r26
+       cmpwi   r3,0
+       beq     99f

which is

+       andis.  r3,r26,(FW_FEATURE_OPAL >> 16)
+       cmpwi   r3,0
+       beq     99f

which is

+       andis.  r3,r26,(FW_FEATURE_OPAL >> 16)
+       beq     99f

> Now, that being said, FW_FEATURE_* can be 64-bit

All of the code above only works for single-bit constants inside
0xffff0000 though (or 0x7fff0000 for the original).

> and this isn't perf
> critical so why not just load the full 64-bit constant into r3 and
> be done with it ? There's a macro to do that:
> 
> 	LOAD_REG_IMMEDIATE(r3,FW_FEATURE_OPAL)

And as you say later, use C.  Yeah.


Segher
diff mbox

Patch

diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 1a74446..60bb626 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -29,6 +29,7 @@ 
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/firmware.h>
 
 int default_machine_kexec_prepare(struct kimage *image)
 {
@@ -313,7 +314,8 @@  struct paca_struct kexec_paca;
 /* Our assembly helper, in misc_64.S */
 extern void kexec_sequence(void *newstack, unsigned long start,
 			   void *image, void *control,
-			   void (*clear_all)(void)) __noreturn;
+			   void (*clear_all)(void),
+			   unsigned long features) __noreturn;
 
 /* too late to fail here */
 void default_machine_kexec(struct kimage *image)
@@ -361,7 +363,7 @@  void default_machine_kexec(struct kimage *image)
 	 */
 	kexec_sequence(&kexec_stack, image->start, image,
 			page_address(image->control_code_page),
-			ppc_md.hpte_clear_all);
+			ppc_md.hpte_clear_all, powerpc_firmware_features);
 	/* NOTREACHED */
 }
 
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 6e4168c..abde07d 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -19,6 +19,7 @@ 
 #include <asm/errno.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/opal.h>
 #include <asm/cache.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
@@ -539,7 +540,7 @@  real_mode:	/* assume normal blr return */
 
 
 /*
- * kexec_sequence(newstack, start, image, control, clear_all())
+ * kexec_sequence(newstack, start, image, control, clear_all(), features)
  *
  * does the grungy work with stack switching and real mode switches
  * also does simple calls to other code
@@ -575,7 +576,7 @@  _GLOBAL(kexec_sequence)
 	mr	r29,r5			/* image (virt) */
 	mr	r28,r6			/* control, unused */
 	mr	r27,r7			/* clear_all() fn desc */
-	mr	r26,r8			/* spare */
+	mr	r26,r8			/* powerpc_firmware_features */
 	lhz	r25,PACAHWCPUID(r13)	/* get our phys cpu from paca */
 
 	/* disable interrupts, we are overwriting kernel data next */
@@ -590,6 +591,20 @@  _GLOBAL(kexec_sequence)
 	/* turn off mmu */
 	bl	real_mode
 
+#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_POWERNV)
+	li	r3,(FW_FEATURE_OPAL >> 16)
+	rldicr	r3,r3,16,63
+	and.	r3,r3,r26
+	cmpwi	r3,0
+	beq	99f
+
+	/* Reset HILE bit now that interrupts are disabled */
+	li	r3,1
+	li	r0,OPAL_REINIT_CPUS
+	bl	opal_call_realmode
+99:
+#endif
+
 	/* copy  0x100 bytes starting at start to 0 */
 	li	r3,0
 	mr	r4,r30		/* start, aka phys mem offset */