Merge branch 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / arch / powerpc / kernel / idle_power7.S
1 /*
2  *  This file contains the power_save function for Power7 CPUs.
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public License
6  *  as published by the Free Software Foundation; either version
7  *  2 of the License, or (at your option) any later version.
8  */
9
10 #include <linux/threads.h>
11 #include <asm/processor.h>
12 #include <asm/page.h>
13 #include <asm/cputable.h>
14 #include <asm/thread_info.h>
15 #include <asm/ppc_asm.h>
16 #include <asm/asm-offsets.h>
17 #include <asm/ppc-opcode.h>
18 #include <asm/hw_irq.h>
19 #include <asm/kvm_book3s_asm.h>
20 #include <asm/opal.h>
21
22 #undef DEBUG
23
24 /* Idle state entry routines */
25
26 #define IDLE_STATE_ENTER_SEQ(IDLE_INST)                         \
27         /* Magic NAP/SLEEP/WINKLE mode enter sequence */        \
28         std     r0,0(r1);                                       \
29         ptesync;                                                \
30         ld      r0,0(r1);                                       \
31 1:      cmp     cr0,r0,r0;                                      \
32         bne     1b;                                             \
33         IDLE_INST;                                              \
34         b       .
35
36         .text
37
38 /*
39  * Pass requested state in r3:
40  *      0 - nap
41  *      1 - sleep
42  */
43 _GLOBAL(power7_powersave_common)
44         /* Use r3 to pass state nap/sleep/winkle */
45         /* NAP is a state loss, we create a regs frame on the
46          * stack, fill it up with the state we care about and
47          * stick a pointer to it in PACAR1. We really only
48          * need to save PC, some CR bits and the NV GPRs,
49          * but for now an interrupt frame will do.
50          */
51         mflr    r0
52         std     r0,16(r1)
53         stdu    r1,-INT_FRAME_SIZE(r1)
54         std     r0,_LINK(r1)
55         std     r0,_NIP(r1)
56
57 #ifndef CONFIG_SMP
58         /* Make sure FPU, VSX etc... are flushed as we may lose
59          * state when going to nap mode
60          */
61         bl      .discard_lazy_cpu_state
62 #endif /* CONFIG_SMP */
63
64         /* Hard disable interrupts */
65         mfmsr   r9
66         rldicl  r9,r9,48,1
67         rotldi  r9,r9,16
68         mtmsrd  r9,1                    /* hard-disable interrupts */
69
70         /* Check if something happened while soft-disabled */
71         lbz     r0,PACAIRQHAPPENED(r13)
72         cmpwi   cr0,r0,0
73         beq     1f
74         addi    r1,r1,INT_FRAME_SIZE
75         ld      r0,16(r1)
76         mtlr    r0
77         blr
78
79 1:      /* We mark irqs hard disabled as this is the state we'll
80          * be in when returning and we need to tell arch_local_irq_restore()
81          * about it
82          */
83         li      r0,PACA_IRQ_HARD_DIS
84         stb     r0,PACAIRQHAPPENED(r13)
85
86         /* We haven't lost state ... yet */
87         li      r0,0
88         stb     r0,PACA_NAPSTATELOST(r13)
89
90         /* Continue saving state */
91         SAVE_GPR(2, r1)
92         SAVE_NVGPRS(r1)
93         mfcr    r4
94         std     r4,_CCR(r1)
95         std     r9,_MSR(r1)
96         std     r1,PACAR1(r13)
97
98 _GLOBAL(power7_enter_nap_mode)
99 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
100         /* Tell KVM we're napping */
101         li      r4,KVM_HWTHREAD_IN_NAP
102         stb     r4,HSTATE_HWTHREAD_STATE(r13)
103 #endif
104         cmpwi   cr0,r3,1
105         beq     2f
106         IDLE_STATE_ENTER_SEQ(PPC_NAP)
107         /* No return */
108 2:      IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
109         /* No return */
110
111 _GLOBAL(power7_idle)
112         /* Now check if user or arch enabled NAP mode */
113         LOAD_REG_ADDRBASE(r3,powersave_nap)
114         lwz     r4,ADDROFF(powersave_nap)(r3)
115         cmpwi   0,r4,0
116         beqlr
117         /* fall through */
118
119 _GLOBAL(power7_nap)
120         li      r3,0
121         b       power7_powersave_common
122         /* No return */
123
124 _GLOBAL(power7_sleep)
125         li      r3,1
126         b       power7_powersave_common
127         /* No return */
128
129 _GLOBAL(power7_wakeup_tb_loss)
130         ld      r2,PACATOC(r13);
131         ld      r1,PACAR1(r13)
132
133         /* Time base re-sync */
134         li      r0,OPAL_RESYNC_TIMEBASE
135         LOAD_REG_ADDR(r11,opal);
136         ld      r12,8(r11);
137         ld      r2,0(r11);
138         mtctr   r12
139         bctrl
140
141         /* TODO: Check r3 for failure */
142
143         REST_NVGPRS(r1)
144         REST_GPR(2, r1)
145         ld      r3,_CCR(r1)
146         ld      r4,_MSR(r1)
147         ld      r5,_NIP(r1)
148         addi    r1,r1,INT_FRAME_SIZE
149         mtcr    r3
150         mfspr   r3,SPRN_SRR1            /* Return SRR1 */
151         mtspr   SPRN_SRR1,r4
152         mtspr   SPRN_SRR0,r5
153         rfid
154
155 _GLOBAL(power7_wakeup_loss)
156         ld      r1,PACAR1(r13)
157         REST_NVGPRS(r1)
158         REST_GPR(2, r1)
159         ld      r3,_CCR(r1)
160         ld      r4,_MSR(r1)
161         ld      r5,_NIP(r1)
162         addi    r1,r1,INT_FRAME_SIZE
163         mtcr    r3
164         mtspr   SPRN_SRR1,r4
165         mtspr   SPRN_SRR0,r5
166         rfid
167
168 _GLOBAL(power7_wakeup_noloss)
169         lbz     r0,PACA_NAPSTATELOST(r13)
170         cmpwi   r0,0
171         bne     .power7_wakeup_loss
172         ld      r1,PACAR1(r13)
173         ld      r4,_MSR(r1)
174         ld      r5,_NIP(r1)
175         addi    r1,r1,INT_FRAME_SIZE
176         mtspr   SPRN_SRR1,r4
177         mtspr   SPRN_SRR0,r5
178         rfid