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
@ -267,6 +267,7 @@ struct machdep_calls {
|
|||||||
|
|
||||||
extern void e500_idle(void);
|
extern void e500_idle(void);
|
||||||
extern void power4_idle(void);
|
extern void power4_idle(void);
|
||||||
|
extern void power7_idle(void);
|
||||||
extern void ppc6xx_idle(void);
|
extern void ppc6xx_idle(void);
|
||||||
extern void book3e_idle(void);
|
extern void book3e_idle(void);
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ struct paca_struct {
|
|||||||
struct task_struct *__current; /* Pointer to current */
|
struct task_struct *__current; /* Pointer to current */
|
||||||
u64 kstack; /* Saved Kernel stack addr */
|
u64 kstack; /* Saved Kernel stack addr */
|
||||||
u64 stab_rr; /* stab/slb round-robin counter */
|
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 */
|
u64 saved_msr; /* MSR saved here by enter_rtas */
|
||||||
u16 trap_save; /* Used when bad stack is encountered */
|
u16 trap_save; /* Used when bad stack is encountered */
|
||||||
u8 soft_enabled; /* irq soft-enable flag */
|
u8 soft_enabled; /* irq soft-enable flag */
|
||||||
|
@ -56,6 +56,9 @@
|
|||||||
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
|
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
|
||||||
#define PPC_INST_XXLOR 0xf0000510
|
#define PPC_INST_XXLOR 0xf0000510
|
||||||
|
|
||||||
|
#define PPC_INST_NAP 0x4c000364
|
||||||
|
#define PPC_INST_SLEEP 0x4c0003a4
|
||||||
|
|
||||||
/* macros to insert fields into opcodes */
|
/* macros to insert fields into opcodes */
|
||||||
#define __PPC_RA(a) (((a) & 0x1f) << 16)
|
#define __PPC_RA(a) (((a) & 0x1f) << 16)
|
||||||
#define __PPC_RB(b) (((b) & 0x1f) << 11)
|
#define __PPC_RB(b) (((b) & 0x1f) << 11)
|
||||||
@ -126,4 +129,7 @@
|
|||||||
#define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \
|
#define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \
|
||||||
VSX_XX3((t), (a), (b)))
|
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 */
|
#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_PPC64) += vdso64/
|
||||||
obj-$(CONFIG_ALTIVEC) += vecemu.o
|
obj-$(CONFIG_ALTIVEC) += vecemu.o
|
||||||
obj-$(CONFIG_PPC_970_NAP) += idle_power4.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_OF) += of_platform.o prom_parse.o
|
||||||
obj-$(CONFIG_PPC_CLOCK) += clock.o
|
obj-$(CONFIG_PPC_CLOCK) += clock.o
|
||||||
procfs-y := proc_powerpc.o
|
procfs-y := proc_powerpc.o
|
||||||
|
@ -37,7 +37,35 @@
|
|||||||
.globl __start_interrupts
|
.globl __start_interrupts
|
||||||
__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
|
. = 0x200
|
||||||
_machine_check_pSeries:
|
_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
|
bool
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config PPC_P7_NAP
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
config PPC_INDIRECT_IO
|
config PPC_INDIRECT_IO
|
||||||
bool
|
bool
|
||||||
select GENERIC_IOMAP
|
select GENERIC_IOMAP
|
||||||
|
Loading…
Reference in New Issue
Block a user