On Fri, 2016-08-05 at 17:34 +0530, Mahesh J Salgaonkar wrote: > From: Mahesh Salgaonkar <mah...@linux.vnet.ibm.com> > > The current implementation of MCE early handling modifies CR0/1 > registers > without saving its old values. Fix this by moving early check for > powersaving mode to machine_check_handle_early().
CC stable ? > The power architecture 2.06 or later allows the possibility of > getting > machine check while in nap/sleep/winkle. The last bit of HSPRG0 is > set > to 1, if thread is woken up from winkle. Hence, clear the last bit of > HSPRG0 (r13) before MCE handler starts using it as paca pointer. > > Also, the current code always puts the thread into nap state > irrespective > of whatever idle state it woke up from. Fix that by looking at > paca->thread_idle_state and put the thread back into same state where > it > came from. > > Reported-by: Paul Mackerras <pau...@samba.org> > Signed-off-by: Mahesh Salgaonkar <mah...@linux.vnet.ibm.com> > Reviewed-by: Shreyas B. Prabhu <shre...@linux.vnet.ibm.com> > --- > Change in v3: > - Rebase to Linus' master. > > Change in v2: > - Call IDLE_STATE_ENTER_SEQ(PPC_NAP) instead of > power7_enter_nap_mode() > to be consistent with other part of code. > --- > arch/powerpc/kernel/exceptions-64s.S | 69 ++++++++++++++++++++-- > ------------ > 1 file changed, 40 insertions(+), 29 deletions(-) > > diff --git a/arch/powerpc/kernel/exceptions-64s.S > b/arch/powerpc/kernel/exceptions-64s.S > index 694def6..a59c9cc 100644 > --- a/arch/powerpc/kernel/exceptions-64s.S > +++ b/arch/powerpc/kernel/exceptions-64s.S > @@ -144,29 +144,14 @@ machine_check_pSeries_1: > * vector > */ > SET_SCRATCH0(r13) /* save r13 */ > -#ifdef CONFIG_PPC_P7_NAP > -BEGIN_FTR_SECTION > - /* Running native on arch 2.06 or later, check if we are > - * waking up from nap. We only handle no state loss and > - * supervisor state loss. We do -not- handle hypervisor > - * state loss at this time. > + /* > + * Running native on arch 2.06 or later, we may wakeup from > winkle > + * inside machine check. If yes, then last bit of HSPGR0 > would be set > + * to 1. Hence clear it unconditionally. > */ > - mfspr r13,SPRN_SRR1 > - rlwinm. r13,r13,47-31,30,31 > - OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) > - beq 9f > - > - mfspr r13,SPRN_SRR1 > - rlwinm. r13,r13,47-31,30,31 > - /* waking up from powersave (nap) state */ > - cmpwi cr1,r13,2 > - /* Total loss of HV state is fatal. let's just stay stuck > here */ > - OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) > - bgt cr1,. > -9: > - OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR) > -END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) > -#endif /* CONFIG_PPC_P7_NAP */ > + GET_PACA(r13) > + clrrdi r13,r13,1 > + SET_PACA(r13) > EXCEPTION_PROLOG_0(PACA_EXMC) > BEGIN_FTR_SECTION > b machine_check_powernv_early > @@ -1273,25 +1258,51 @@ machine_check_handle_early: > * Check if thread was in power saving mode. We come here > when any > * of the following is true: > * a. thread wasn't in power saving mode > - * b. thread was in power saving mode with no state loss or > - * supervisor state loss > + * b. thread was in power saving mode with no state loss, > + * supervisor state loss or hypervisor state loss. > * > - * Go back to nap again if (b) is true. > + * Go back to nap/sleep/winkle mode again if (b) is true. > */ > rlwinm. r11,r12,47-31,30,31 /* Was it in power > saving mode? */ > beq 4f /* No, it wasn;t */ > /* Thread was in power saving mode. Go back to nap again. */ > cmpwi r11,2 > - bne 3f > - /* Supervisor state loss */ > + blt 3f > + /* Supervisor/Hypervisor state loss */ > li r0,1 > stb r0,PACA_NAPSTATELOST(r13) > 3: bl machine_check_queue_event > MACHINE_CHECK_HANDLER_WINDUP > GET_PACA(r13) > ld r1,PACAR1(r13) > - li r3,PNV_THREAD_NAP > - b pnv_enter_arch207_idle_mode > + /* > + * Check what idle state this CPU was in and go back to same > mode > + * again. > + */ > + lbz r3,PACA_THREAD_IDLE_STATE(r13) > + cmpwi r3,PNV_THREAD_NAP > + bgt 10f > + IDLE_STATE_ENTER_SEQ(PPC_NAP) > + /* No return */ > +10: > + cmpwi r3,PNV_THREAD_SLEEP > + bgt 2f > + IDLE_STATE_ENTER_SEQ(PPC_SLEEP) > + /* No return */ > + > +2: > + /* > + * Go back to winkle. Please note that this thread was woken > up in > + * machine check from winkle and have not restored the per- > subcore > + * state. Hence before going back to winkle, set last bit of > HSPGR0 > + * to 1. This will make sure that if this thread gets woken > up > + * again at reset vector 0x100 then it will get chance to > restore > + * the subcore state. > + */ > + ori r13,r13,1 > + SET_PACA(r13) > + IDLE_STATE_ENTER_SEQ(PPC_WINKLE) > + /* No return */ > 4: > #endif > /*