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:
Родитель
9d07bc841c
Коммит
948cf67c47
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче