powerpc: Add NAP mode support on Power7 in HV mode
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 24 Jan 2011 07:42:41 +0000 (18:42 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 20 Apr 2011 01:03:24 +0000 (11:03 +1000)
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>
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/idle_power7.S [new file with mode: 0644]
arch/powerpc/platforms/Kconfig

index e4f0191..493dbb3 100644 (file)
@@ -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);
 
index ec57540..f6da4f5 100644 (file)
@@ -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 */
index 1255569..384a96d 100644 (file)
@@ -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)
 #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 */
index 7c6eb49..0fd6273 100644 (file)
@@ -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
index e513c1d..ad06333 100644 (file)
        .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:
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
new file mode 100644 (file)
index 0000000..f8f0bc7
--- /dev/null
@@ -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
index f7b0772..658ffc5 100644 (file)
@@ -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