diff options
Diffstat (limited to 'arch/powerpc/kernel/idle_power7.S')
| -rw-r--r-- | arch/powerpc/kernel/idle_power7.S | 106 | 
1 files changed, 84 insertions, 22 deletions
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index e11863f4e59..5cf3d367190 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -17,20 +17,35 @@  #include <asm/ppc-opcode.h>  #include <asm/hw_irq.h>  #include <asm/kvm_book3s_asm.h> +#include <asm/opal.h>  #undef DEBUG -	.text +/* Idle state entry routines */ -_GLOBAL(power7_idle) -	/* Now check if user or arch enabled NAP mode */ -	LOAD_REG_ADDRBASE(r3,powersave_nap) -	lwz	r4,ADDROFF(powersave_nap)(r3) -	cmpwi	0,r4,0 -	beqlr -	/* fall through */ +#define	IDLE_STATE_ENTER_SEQ(IDLE_INST)				\ +	/* Magic NAP/SLEEP/WINKLE mode enter sequence */	\ +	std	r0,0(r1);					\ +	ptesync;						\ +	ld	r0,0(r1);					\ +1:	cmp	cr0,r0,r0;					\ +	bne	1b;						\ +	IDLE_INST;						\ +	b	. -_GLOBAL(power7_nap) +	.text + +/* + * Pass requested state in r3: + * 	0 - nap + * 	1 - sleep + * + * To check IRQ_HAPPENED in r4 + * 	0 - don't check + * 	1 - check + */ +_GLOBAL(power7_powersave_common) +	/* Use r3 to pass state nap/sleep/winkle */  	/* NAP is a state loss, we create a regs frame on the  	 * stack, fill it up with the state we care about and  	 * stick a pointer to it in PACAR1. We really only @@ -47,7 +62,7 @@ _GLOBAL(power7_nap)  	/* Make sure FPU, VSX etc... are flushed as we may lose  	 * state when going to nap mode  	 */ -	bl	.discard_lazy_cpu_state +	bl	discard_lazy_cpu_state  #endif /* CONFIG_SMP */  	/* Hard disable interrupts */ @@ -60,6 +75,8 @@ _GLOBAL(power7_nap)  	lbz	r0,PACAIRQHAPPENED(r13)  	cmpwi	cr0,r0,0  	beq	1f +	cmpwi	cr0,r4,0 +	beq	1f  	addi	r1,r1,INT_FRAME_SIZE  	ld	r0,16(r1)  	mtlr	r0 @@ -79,25 +96,70 @@ _GLOBAL(power7_nap)  	/* Continue saving state */  	SAVE_GPR(2, r1)  	SAVE_NVGPRS(r1) -	mfcr	r3 -	std	r3,_CCR(r1) +	mfcr	r4 +	std	r4,_CCR(r1)  	std	r9,_MSR(r1)  	std	r1,PACAR1(r13) -#ifdef CONFIG_KVM_BOOK3S_64_HV +_GLOBAL(power7_enter_nap_mode) +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE  	/* Tell KVM we're napping */  	li	r4,KVM_HWTHREAD_IN_NAP  	stb	r4,HSTATE_HWTHREAD_STATE(r13)  #endif +	cmpwi	cr0,r3,1 +	beq	2f +	IDLE_STATE_ENTER_SEQ(PPC_NAP) +	/* No return */ +2:	IDLE_STATE_ENTER_SEQ(PPC_SLEEP) +	/* No return */ -	/* Magic NAP mode enter sequence */ -	std	r0,0(r1) -	ptesync -	ld	r0,0(r1) -1:	cmp	cr0,r0,r0 -	bne	1b -	PPC_NAP -	b	. +_GLOBAL(power7_idle) +	/* Now check if user or arch enabled NAP mode */ +	LOAD_REG_ADDRBASE(r3,powersave_nap) +	lwz	r4,ADDROFF(powersave_nap)(r3) +	cmpwi	0,r4,0 +	beqlr +	li	r3, 1 +	/* fall through */ + +_GLOBAL(power7_nap) +	mr	r4,r3 +	li	r3,0 +	b	power7_powersave_common +	/* No return */ + +_GLOBAL(power7_sleep) +	li	r3,1 +	li	r4,1 +	b	power7_powersave_common +	/* No return */ + +_GLOBAL(power7_wakeup_tb_loss) +	ld	r2,PACATOC(r13); +	ld	r1,PACAR1(r13) + +	/* Time base re-sync */ +	li	r0,OPAL_RESYNC_TIMEBASE +	LOAD_REG_ADDR(r11,opal); +	ld	r12,8(r11); +	ld	r2,0(r11); +	mtctr	r12 +	bctrl + +	/* TODO: Check r3 for failure */ + +	REST_NVGPRS(r1) +	REST_GPR(2, r1) +	ld	r3,_CCR(r1) +	ld	r4,_MSR(r1) +	ld	r5,_NIP(r1) +	addi	r1,r1,INT_FRAME_SIZE +	mtcr	r3 +	mfspr	r3,SPRN_SRR1		/* Return SRR1 */ +	mtspr	SPRN_SRR1,r4 +	mtspr	SPRN_SRR0,r5 +	rfid  _GLOBAL(power7_wakeup_loss)  	ld	r1,PACAR1(r13) @@ -115,7 +177,7 @@ _GLOBAL(power7_wakeup_loss)  _GLOBAL(power7_wakeup_noloss)  	lbz	r0,PACA_NAPSTATELOST(r13)  	cmpwi	r0,0 -	bne	.power7_wakeup_loss +	bne	power7_wakeup_loss  	ld	r1,PACAR1(r13)  	ld	r4,_MSR(r1)  	ld	r5,_NIP(r1)  | 
