]>
Commit | Line | Data |
---|---|---|
948cf67c | 1 | /* |
7230c564 | 2 | * This file contains the power_save function for Power7 CPUs. |
948cf67c BH |
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> | |
7230c564 | 18 | #include <asm/hw_irq.h> |
f0888f70 | 19 | #include <asm/kvm_book3s_asm.h> |
97eb001f | 20 | #include <asm/opal.h> |
948cf67c BH |
21 | |
22 | #undef DEBUG | |
23 | ||
aca79d2b | 24 | /* Idle state entry routines */ |
948cf67c | 25 | |
aca79d2b VS |
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 . | |
948cf67c | 35 | |
aca79d2b VS |
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 */ | |
948cf67c BH |
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 | */ | |
b1576fec | 61 | bl discard_lazy_cpu_state |
948cf67c BH |
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 */ | |
7230c564 BH |
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 */ | |
948cf67c | 87 | li r0,0 |
2fde6d20 | 88 | stb r0,PACA_NAPSTATELOST(r13) |
948cf67c BH |
89 | |
90 | /* Continue saving state */ | |
91 | SAVE_GPR(2, r1) | |
92 | SAVE_NVGPRS(r1) | |
aca79d2b VS |
93 | mfcr r4 |
94 | std r4,_CCR(r1) | |
948cf67c BH |
95 | std r9,_MSR(r1) |
96 | std r1,PACAR1(r13) | |
97 | ||
1c51089f | 98 | _GLOBAL(power7_enter_nap_mode) |
9975f5e3 | 99 | #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE |
f0888f70 PM |
100 | /* Tell KVM we're napping */ |
101 | li r4,KVM_HWTHREAD_IN_NAP | |
102 | stb r4,HSTATE_HWTHREAD_STATE(r13) | |
103 | #endif | |
aca79d2b VS |
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 */ | |
f0888f70 | 110 | |
aca79d2b VS |
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 */ | |
948cf67c | 128 | |
97eb001f VS |
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 | ||
948cf67c | 155 | _GLOBAL(power7_wakeup_loss) |
948cf67c BH |
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) | |
2fde6d20 PM |
169 | lbz r0,PACA_NAPSTATELOST(r13) |
170 | cmpwi r0,0 | |
b1576fec | 171 | bne power7_wakeup_loss |
948cf67c BH |
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 |