mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	powerpc: Add NAP mode support on Power7 in HV mode
Wakeup comes from the system reset handler with a potential loss of the non-hypervisor CPU state. We save the non-volatile state on the stack and a pointer to it in the PACA, which the system reset handler uses to restore things Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
		
							parent
							
								
									9d07bc841c
								
							
						
					
					
						commit
						948cf67c47
					
				
					 7 changed files with 139 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -267,6 +267,7 @@ struct machdep_calls {
 | 
			
		|||
 | 
			
		||||
extern void e500_idle(void);
 | 
			
		||||
extern void power4_idle(void);
 | 
			
		||||
extern void power7_idle(void);
 | 
			
		||||
extern void ppc6xx_idle(void);
 | 
			
		||||
extern void book3e_idle(void);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ struct paca_struct {
 | 
			
		|||
	struct task_struct *__current;	/* Pointer to current */
 | 
			
		||||
	u64 kstack;			/* Saved Kernel stack addr */
 | 
			
		||||
	u64 stab_rr;			/* stab/slb round-robin counter */
 | 
			
		||||
	u64 saved_r1;			/* r1 save for RTAS calls */
 | 
			
		||||
	u64 saved_r1;			/* r1 save for RTAS calls or PM */
 | 
			
		||||
	u64 saved_msr;			/* MSR saved here by enter_rtas */
 | 
			
		||||
	u16 trap_save;			/* Used when bad stack is encountered */
 | 
			
		||||
	u8 soft_enabled;		/* irq soft-enable flag */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,9 @@
 | 
			
		|||
#define PPC_INST_TLBSRX_DOT		0x7c0006a5
 | 
			
		||||
#define PPC_INST_XXLOR			0xf0000510
 | 
			
		||||
 | 
			
		||||
#define PPC_INST_NAP			0x4c000364
 | 
			
		||||
#define PPC_INST_SLEEP			0x4c0003a4
 | 
			
		||||
 | 
			
		||||
/* macros to insert fields into opcodes */
 | 
			
		||||
#define __PPC_RA(a)	(((a) & 0x1f) << 16)
 | 
			
		||||
#define __PPC_RB(b)	(((b) & 0x1f) << 11)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,4 +129,7 @@
 | 
			
		|||
#define XXLOR(t, a, b)		stringify_in_c(.long PPC_INST_XXLOR | \
 | 
			
		||||
					       VSX_XX3((t), (a), (b)))
 | 
			
		||||
 | 
			
		||||
#define PPC_NAP			stringify_in_c(.long PPC_INST_NAP)
 | 
			
		||||
#define PPC_SLEEP		stringify_in_c(.long PPC_INST_SLEEP)
 | 
			
		||||
 | 
			
		||||
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_book3e.o
 | 
			
		|||
obj-$(CONFIG_PPC64)		+= vdso64/
 | 
			
		||||
obj-$(CONFIG_ALTIVEC)		+= vecemu.o
 | 
			
		||||
obj-$(CONFIG_PPC_970_NAP)	+= idle_power4.o
 | 
			
		||||
obj-$(CONFIG_PPC_P7_NAP)	+= idle_power7.o
 | 
			
		||||
obj-$(CONFIG_PPC_OF)		+= of_platform.o prom_parse.o
 | 
			
		||||
obj-$(CONFIG_PPC_CLOCK)		+= clock.o
 | 
			
		||||
procfs-y			:= proc_powerpc.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,35 @@
 | 
			
		|||
	.globl __start_interrupts
 | 
			
		||||
__start_interrupts:
 | 
			
		||||
 | 
			
		||||
	STD_EXCEPTION_PSERIES(0x100, 0x100, system_reset)
 | 
			
		||||
	.globl system_reset_pSeries;
 | 
			
		||||
system_reset_pSeries:
 | 
			
		||||
	HMT_MEDIUM;
 | 
			
		||||
	DO_KVM	0x100;
 | 
			
		||||
	SET_SCRATCH0(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.
 | 
			
		||||
	 */
 | 
			
		||||
	mfspr	r13,SPRN_SRR1
 | 
			
		||||
	rlwinm	r13,r13,47-31,30,31
 | 
			
		||||
	cmpwi	cr0,r13,1
 | 
			
		||||
	bne	1f
 | 
			
		||||
	b	.power7_wakeup_noloss
 | 
			
		||||
1:	cmpwi	cr0,r13,2
 | 
			
		||||
	bne	1f
 | 
			
		||||
	b	.power7_wakeup_loss
 | 
			
		||||
	/* Total loss of HV state is fatal, we could try to use the
 | 
			
		||||
	 * PIR to locate a PACA, then use an emergency stack etc...
 | 
			
		||||
	 * but for now, let's just stay stuck here
 | 
			
		||||
	 */
 | 
			
		||||
1:	cmpwi	cr0,r13,3
 | 
			
		||||
	beq	.
 | 
			
		||||
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE_206)
 | 
			
		||||
#endif /* CONFIG_PPC_P7_NAP */
 | 
			
		||||
	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD)
 | 
			
		||||
 | 
			
		||||
	. = 0x200
 | 
			
		||||
_machine_check_pSeries:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										97
									
								
								arch/powerpc/kernel/idle_power7.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								arch/powerpc/kernel/idle_power7.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,97 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  This file contains the power_save function for 970-family CPUs.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or
 | 
			
		||||
 *  modify it under the terms of the GNU General Public License
 | 
			
		||||
 *  as published by the Free Software Foundation; either version
 | 
			
		||||
 *  2 of the License, or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/threads.h>
 | 
			
		||||
#include <asm/processor.h>
 | 
			
		||||
#include <asm/page.h>
 | 
			
		||||
#include <asm/cputable.h>
 | 
			
		||||
#include <asm/thread_info.h>
 | 
			
		||||
#include <asm/ppc_asm.h>
 | 
			
		||||
#include <asm/asm-offsets.h>
 | 
			
		||||
#include <asm/ppc-opcode.h>
 | 
			
		||||
 | 
			
		||||
#undef DEBUG
 | 
			
		||||
 | 
			
		||||
	.text
 | 
			
		||||
 | 
			
		||||
_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
 | 
			
		||||
 | 
			
		||||
	/* 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
 | 
			
		||||
	 * need to save PC, some CR bits and the NV GPRs,
 | 
			
		||||
	 * but for now an interrupt frame will do.
 | 
			
		||||
	 */
 | 
			
		||||
	mflr	r0
 | 
			
		||||
	std	r0,16(r1)
 | 
			
		||||
	stdu	r1,-INT_FRAME_SIZE(r1)
 | 
			
		||||
	std	r0,_LINK(r1)
 | 
			
		||||
	std	r0,_NIP(r1)
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_SMP
 | 
			
		||||
	/* Make sure FPU, VSX etc... are flushed as we may lose
 | 
			
		||||
	 * state when going to nap mode
 | 
			
		||||
	 */
 | 
			
		||||
	bl	.discard_lazy_cpu_state
 | 
			
		||||
#endif /* CONFIG_SMP */
 | 
			
		||||
 | 
			
		||||
	/* Hard disable interrupts */
 | 
			
		||||
	mfmsr	r9
 | 
			
		||||
	rldicl	r9,r9,48,1
 | 
			
		||||
	rotldi	r9,r9,16
 | 
			
		||||
	mtmsrd	r9,1			/* hard-disable interrupts */
 | 
			
		||||
	li	r0,0
 | 
			
		||||
	stb	r0,PACASOFTIRQEN(r13)	/* we'll hard-enable shortly */
 | 
			
		||||
	stb	r0,PACAHARDIRQEN(r13)
 | 
			
		||||
 | 
			
		||||
	/* Continue saving state */
 | 
			
		||||
	SAVE_GPR(2, r1)
 | 
			
		||||
	SAVE_NVGPRS(r1)
 | 
			
		||||
	mfcr	r3
 | 
			
		||||
	std	r3,_CCR(r1)
 | 
			
		||||
	std	r9,_MSR(r1)
 | 
			
		||||
	std	r1,PACAR1(r13)
 | 
			
		||||
 | 
			
		||||
	/* 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_wakeup_loss)
 | 
			
		||||
	GET_PACA(r13)
 | 
			
		||||
	ld	r1,PACAR1(r13)
 | 
			
		||||
	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
 | 
			
		||||
	mtspr	SPRN_SRR1,r4
 | 
			
		||||
	mtspr	SPRN_SRR0,r5
 | 
			
		||||
	rfid
 | 
			
		||||
 | 
			
		||||
_GLOBAL(power7_wakeup_noloss)
 | 
			
		||||
	GET_PACA(r13)
 | 
			
		||||
	ld	r1,PACAR1(r13)
 | 
			
		||||
	ld	r4,_MSR(r1)
 | 
			
		||||
	ld	r5,_NIP(r1)
 | 
			
		||||
	addi	r1,r1,INT_FRAME_SIZE
 | 
			
		||||
	mtspr	SPRN_SRR1,r4
 | 
			
		||||
	mtspr	SPRN_SRR0,r5
 | 
			
		||||
	rfid
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +147,10 @@ config PPC_970_NAP
 | 
			
		|||
	bool
 | 
			
		||||
	default n
 | 
			
		||||
 | 
			
		||||
config PPC_P7_NAP
 | 
			
		||||
	bool
 | 
			
		||||
	default n
 | 
			
		||||
 | 
			
		||||
config PPC_INDIRECT_IO
 | 
			
		||||
	bool
 | 
			
		||||
	select GENERIC_IOMAP
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue