]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | #include <ppc/asm.h> | |
29 | #include <ppc/proc_reg.h> | |
1c79356b A |
30 | #include <assym.s> |
31 | #include <debug.h> | |
32 | #include <mach/ppc/vm_param.h> | |
33 | #include <ppc/exception.h> | |
34 | ||
55e303ae A |
35 | |
36 | /* | |
37 | * ml_set_physical() -- turn off DR and (if 64-bit) turn SF on | |
38 | * it is assumed that pf64Bit is already in cr6 | |
39 | * ml_set_physical_get_ffs() -- turn DR off, SF on, and get feature flags | |
40 | * ml_set_physical_disabled() -- turn DR and EE off, SF on, get feature flags | |
41 | * ml_set_translation_off() -- turn DR, IR, and EE off, SF on, get feature flags | |
42 | * | |
43 | * Callable only from assembler, these return: | |
44 | * r2 -- new MSR | |
45 | * r11 -- old MSR | |
46 | * r10 -- feature flags (pf64Bit etc, ie SPRG 2) | |
47 | * cr6 -- feature flags 24-27, ie pf64Bit, pf128Byte, and pf32Byte | |
48 | * | |
49 | * Uses r0 and r2. ml_set_translation_off also uses r3 and cr5. | |
50 | */ | |
51 | ||
52 | .align 4 | |
53 | .globl EXT(ml_set_translation_off) | |
54 | LEXT(ml_set_translation_off) | |
55 | mfsprg r10,2 // get feature flags | |
56 | li r0,0 ; Clear this | |
57 | mtcrf 0x02,r10 // move pf64Bit etc to cr6 | |
58 | ori r0,r0,lo16(MASK(MSR_EE)+MASK(MSR_FP)+MASK(MSR_IR)+MASK(MSR_DR)) // turn off all 4 | |
59 | mfmsr r11 // get MSR | |
60 | oris r0,r0,hi16(MASK(MSR_VEC)) // Turn off vector too | |
61 | mtcrf 0x04,r10 // move pfNoMSRir etc to cr5 | |
62 | andc r2,r11,r0 // turn off EE, IR, and DR | |
63 | bt++ pf64Bitb,ml_set_physical_64 // skip if 64-bit (only they take the hint) | |
64 | bf pfNoMSRirb,ml_set_physical_32 // skip if we can load MSR directly | |
65 | li r0,loadMSR // Get the MSR setter SC | |
66 | mr r3,r2 // copy new MSR to r2 | |
67 | sc // Set it | |
68 | blr | |
69 | ||
70 | .align 4 | |
71 | .globl EXT(ml_set_physical_disabled) | |
72 | ||
73 | LEXT(ml_set_physical_disabled) | |
74 | li r0,0 ; Clear | |
75 | mfsprg r10,2 // get feature flags | |
76 | ori r0,r0,lo16(MASK(MSR_EE)) // turn EE and fp off | |
77 | mtcrf 0x02,r10 // move pf64Bit etc to cr6 | |
78 | b ml_set_physical_join | |
79 | ||
80 | .align 5 | |
81 | .globl EXT(ml_set_physical_get_ffs) | |
82 | ||
83 | LEXT(ml_set_physical_get_ffs) | |
84 | mfsprg r10,2 // get feature flags | |
85 | mtcrf 0x02,r10 // move pf64Bit etc to cr6 | |
86 | ||
87 | .globl EXT(ml_set_physical) | |
88 | LEXT(ml_set_physical) | |
89 | ||
90 | li r0,0 // do not turn off interrupts | |
91 | ||
92 | ml_set_physical_join: | |
93 | oris r0,r0,hi16(MASK(MSR_VEC)) // Always gonna turn of vectors | |
94 | mfmsr r11 // get MSR | |
95 | ori r0,r0,lo16(MASK(MSR_DR)+MASK(MSR_FP)) // always turn off DR and FP bit | |
96 | andc r2,r11,r0 // turn off DR and maybe EE | |
97 | bt++ pf64Bitb,ml_set_physical_64 // skip if 64-bit (only they take the hint) | |
98 | ml_set_physical_32: | |
99 | mtmsr r2 // turn off translation | |
100 | isync | |
101 | blr | |
102 | ||
103 | ml_set_physical_64: | |
104 | li r0,1 // get a 1 to slam into SF | |
105 | rldimi r2,r0,63,MSR_SF_BIT // set SF bit (bit 0) | |
106 | mtmsrd r2 // set 64-bit mode, turn off data relocation | |
107 | isync // synchronize | |
108 | blr | |
109 | ||
110 | ||
111 | /* | |
112 | * ml_restore(old_MSR) | |
113 | * | |
114 | * Callable only from assembler, restores the MSR in r11 saved by ml_set_physical. | |
115 | * We assume cr6 and r11 are as set by ml_set_physical, ie: | |
116 | * cr6 - pf64Bit flag (feature flags 24-27) | |
117 | * r11 - old MSR | |
118 | */ | |
119 | ||
120 | .align 5 | |
121 | .globl EXT(ml_restore) | |
122 | ||
123 | LEXT(ml_restore) | |
124 | bt++ pf64Bitb,ml_restore_64 // handle 64-bit cpus (only they take the hint) | |
125 | mtmsr r11 // restore a 32-bit MSR | |
126 | isync | |
127 | blr | |
128 | ||
129 | ml_restore_64: | |
130 | mtmsrd r11 // restore a 64-bit MSR | |
131 | isync | |
132 | blr | |
133 | ||
134 | ||
1c79356b A |
135 | /* PCI config cycle probing |
136 | * | |
137 | * boolean_t ml_probe_read(vm_offset_t paddr, unsigned int *val) | |
138 | * | |
139 | * Read the memory location at physical address paddr. | |
140 | * This is a part of a device probe, so there is a good chance we will | |
141 | * have a machine check here. So we have to be able to handle that. | |
142 | * We assume that machine checks are enabled both in MSR and HIDs | |
143 | */ | |
144 | ||
145 | ; Force a line boundry here | |
146 | .align 5 | |
147 | .globl EXT(ml_probe_read) | |
148 | ||
149 | LEXT(ml_probe_read) | |
150 | ||
151 | mfsprg r9,2 ; Get feature flags | |
55e303ae A |
152 | |
153 | rlwinm. r0,r9,0,pf64Bitb,pf64Bitb ; Are we on a 64-bit machine? | |
154 | rlwinm r3,r3,0,0,31 ; Clean up for 64-bit machines | |
155 | bne++ mpr64bit ; Go do this the 64-bit way... | |
156 | ||
157 | mpr32bit: lis r8,hi16(MASK(MSR_VEC)) ; Get the vector flag | |
1c79356b | 158 | mfmsr r0 ; Save the current MSR |
55e303ae A |
159 | ori r8,r8,lo16(MASK(MSR_FP)) ; Add the FP flag |
160 | ||
1c79356b | 161 | neg r10,r3 ; Number of bytes to end of page |
55e303ae | 162 | andc r0,r0,r8 ; Clear VEC and FP |
1c79356b | 163 | rlwinm. r10,r10,0,20,31 ; Clear excess junk and test for page bndry |
55e303ae | 164 | ori r8,r8,lo16(MASK(MSR_EE)|MASK(MSR_IR)|MASK(MSR_DR)) ; Drop EE, IR, and DR |
1c79356b | 165 | mr r12,r3 ; Save the load address |
55e303ae | 166 | andc r2,r0,r8 ; Clear VEC, FP, and EE |
1c79356b A |
167 | mtcrf 0x04,r9 ; Set the features |
168 | cmplwi cr1,r10,4 ; At least 4 bytes left in page? | |
1c79356b A |
169 | beq- mprdoit ; We are right on the boundary... |
170 | li r3,0 | |
171 | bltlr- cr1 ; No, just return failure... | |
172 | ||
173 | mprdoit: | |
174 | ||
175 | bt pfNoMSRirb,mprNoMSR ; No MSR... | |
176 | ||
177 | mtmsr r2 ; Translation and all off | |
178 | isync ; Toss prefetch | |
179 | b mprNoMSRx | |
180 | ||
181 | mprNoMSR: | |
182 | mr r5,r0 | |
183 | li r0,loadMSR ; Get the MSR setter SC | |
184 | mr r3,r2 ; Get new MSR | |
185 | sc ; Set it | |
186 | mr r0,r5 | |
187 | li r3,0 | |
188 | mprNoMSRx: | |
d52fe63f A |
189 | |
190 | mfspr r6, hid0 ; Get a copy of hid0 | |
1c79356b | 191 | |
9bccf70c A |
192 | rlwinm. r5, r9, 0, pfNoMuMMCKb, pfNoMuMMCKb ; Check for NoMuMMCK |
193 | bne mprNoMuM | |
194 | ||
195 | rlwinm r5, r6, 0, ice+1, ice-1 ; Turn off L1 I-Cache | |
196 | mtspr hid0, r5 | |
197 | isync ; Wait for I-Cache off | |
198 | rlwinm r5, r6, 0, mum+1, mum-1 ; Turn off MuM w/ I-Cache on | |
199 | mtspr hid0, r5 | |
200 | mprNoMuM: | |
d52fe63f | 201 | |
1c79356b A |
202 | ; |
203 | ; We need to insure that there is no more than 1 BAT register that | |
204 | ; can get a hit. There could be repercussions beyond the ken | |
205 | ; of mortal man. It is best not to tempt fate. | |
206 | ; | |
d52fe63f A |
207 | |
208 | ; Note: we will reload these from the shadow BATs later | |
209 | ||
1c79356b | 210 | li r10,0 ; Clear a register |
1c79356b A |
211 | |
212 | sync ; Make sure all is well | |
213 | ||
214 | mtdbatu 1,r10 ; Invalidate DBAT 1 | |
215 | mtdbatu 2,r10 ; Invalidate DBAT 2 | |
216 | mtdbatu 3,r10 ; Invalidate DBAT 3 | |
217 | ||
218 | rlwinm r10,r12,0,0,14 ; Round down to a 128k boundary | |
219 | ori r11,r10,0x32 ; Set uncached, coherent, R/W | |
220 | ori r10,r10,2 ; Make the upper half (128k, valid supervisor) | |
221 | mtdbatl 0,r11 ; Set lower BAT first | |
222 | mtdbatu 0,r10 ; Now the upper | |
223 | sync ; Just make sure | |
224 | ||
d52fe63f A |
225 | dcbf 0,r12 ; Make sure we kill the cache to avoid paradoxes |
226 | sync | |
227 | ||
1c79356b A |
228 | ori r11,r2,lo16(MASK(MSR_DR)) ; Turn on data translation |
229 | mtmsr r11 ; Do it for real | |
230 | isync ; Make sure of it | |
231 | ||
232 | eieio ; Make sure of all previous accesses | |
233 | sync ; Make sure it is all caught up | |
234 | ||
235 | lwz r11,0(r12) ; Get it and maybe machine check here | |
236 | ||
237 | eieio ; Make sure of ordering again | |
238 | sync ; Get caught up yet again | |
239 | isync ; Do not go further till we are here | |
240 | ||
d52fe63f A |
241 | mtmsr r2 ; Turn translation back off |
242 | isync | |
243 | ||
d52fe63f A |
244 | lis r10,hi16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address |
245 | ori r10,r10,lo16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address | |
246 | ||
247 | lwz r5,0(r10) ; Pick up DBAT 0 high | |
248 | lwz r6,4(r10) ; Pick up DBAT 0 low | |
249 | lwz r7,8(r10) ; Pick up DBAT 1 high | |
250 | lwz r8,16(r10) ; Pick up DBAT 2 high | |
251 | lwz r9,24(r10) ; Pick up DBAT 3 high | |
252 | ||
1c79356b A |
253 | mtdbatu 0,r5 ; Restore DBAT 0 high |
254 | mtdbatl 0,r6 ; Restore DBAT 0 low | |
255 | mtdbatu 1,r7 ; Restore DBAT 1 high | |
256 | mtdbatu 2,r8 ; Restore DBAT 2 high | |
257 | mtdbatu 3,r9 ; Restore DBAT 3 high | |
258 | sync | |
259 | ||
260 | li r3,1 ; We made it | |
261 | ||
262 | mtmsr r0 ; Restore translation and exceptions | |
263 | isync ; Toss speculations | |
264 | ||
265 | stw r11,0(r4) ; Save the loaded value | |
266 | blr ; Return... | |
267 | ||
268 | ; Force a line boundry here. This means we will be able to check addresses better | |
269 | .align 5 | |
270 | .globl EXT(ml_probe_read_mck) | |
271 | LEXT(ml_probe_read_mck) | |
272 | ||
55e303ae A |
273 | |
274 | /* PCI config cycle probing - 64-bit | |
275 | * | |
276 | * boolean_t ml_probe_read_64(addr64_t paddr, unsigned int *val) | |
277 | * | |
278 | * Read the memory location at physical address paddr. | |
279 | * This is a part of a device probe, so there is a good chance we will | |
280 | * have a machine check here. So we have to be able to handle that. | |
281 | * We assume that machine checks are enabled both in MSR and HIDs | |
282 | */ | |
283 | ||
284 | ; Force a line boundry here | |
285 | .align 6 | |
286 | .globl EXT(ml_probe_read_64) | |
287 | ||
288 | LEXT(ml_probe_read_64) | |
289 | ||
290 | mfsprg r9,2 ; Get feature flags | |
291 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
292 | rlwinm. r0,r9,0,pf64Bitb,pf64Bitb ; Are we on a 64-bit machine? | |
293 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
294 | ||
295 | mr r4,r5 ; Move result to common register | |
296 | beq-- mpr32bit ; Go do this the 32-bit way... | |
297 | ||
298 | mpr64bit: andi. r0,r3,3 ; Check if we are on a word boundary | |
299 | li r0,0 ; Clear the EE bit (and everything else for that matter) | |
300 | bne-- mprFail ; Boundary not good... | |
301 | mfmsr r11 ; Get the MSR | |
302 | mtmsrd r0,1 ; Set the EE bit only (do not care about RI) | |
303 | rlwinm r11,r11,0,MSR_EE_BIT,MSR_EE_BIT ; Isolate just the EE bit | |
304 | mfmsr r10 ; Refresh our view of the MSR (VMX/FP may have changed) | |
305 | or r12,r10,r11 ; Turn on EE if on before we turned it off | |
306 | ori r0,r0,lo16(MASK(MSR_IR)|MASK(MSR_DR)) ; Get the IR and DR bits | |
307 | li r2,1 ; Get a 1 | |
308 | sldi r2,r2,63 ; Get the 64-bit bit | |
309 | andc r10,r10,r0 ; Clear IR and DR | |
310 | or r10,r10,r2 ; Set 64-bit | |
311 | ||
312 | li r0,1 ; Get a 1 | |
313 | mtmsrd r10 ; Translation and EE off, 64-bit on | |
314 | isync | |
315 | ||
316 | sldi r0,r0,32+8 ; Get the right bit to inhibit caching | |
317 | ||
318 | mfspr r8,hid4 ; Get HID4 | |
319 | or r2,r8,r0 ; Set bit to make real accesses cache-inhibited | |
320 | sync ; Sync up | |
321 | mtspr hid4,r2 ; Make real accesses cache-inhibited | |
322 | isync ; Toss prefetches | |
323 | ||
324 | lis r7,0xE000 ; Get the unlikeliest ESID possible | |
325 | srdi r7,r7,1 ; Make 0x7FFFFFFFF0000000 | |
326 | slbie r7 ; Make sure the ERAT is cleared | |
327 | ||
328 | sync | |
329 | isync | |
330 | ||
331 | eieio ; Make sure of all previous accesses | |
332 | ||
333 | lwz r11,0(r3) ; Get it and maybe machine check here | |
334 | ||
335 | eieio ; Make sure of ordering again | |
336 | sync ; Get caught up yet again | |
337 | isync ; Do not go further till we are here | |
338 | ||
339 | sync ; Sync up | |
340 | mtspr hid4,r8 ; Make real accesses not cache-inhibited | |
341 | isync ; Toss prefetches | |
342 | ||
343 | lis r7,0xE000 ; Get the unlikeliest ESID possible | |
344 | srdi r7,r7,1 ; Make 0x7FFFFFFFF0000000 | |
345 | slbie r7 ; Make sure the ERAT is cleared | |
346 | ||
347 | mtmsrd r12 ; Restore entry MSR | |
348 | isync | |
349 | ||
350 | stw r11,0(r4) ; Pass back the result | |
351 | li r3,1 ; Indicate success | |
352 | blr ; Leave... | |
353 | ||
354 | mprFail: li r3,0 ; Set failure | |
355 | blr ; Leave... | |
356 | ||
357 | ; Force a line boundry here. This means we will be able to check addresses better | |
358 | .align 6 | |
359 | .globl EXT(ml_probe_read_mck_64) | |
360 | LEXT(ml_probe_read_mck_64) | |
361 | ||
362 | ||
363 | /* Read physical address byte | |
1c79356b A |
364 | * |
365 | * unsigned int ml_phys_read_byte(vm_offset_t paddr) | |
55e303ae | 366 | * unsigned int ml_phys_read_byte_64(addr64_t paddr) |
1c79356b A |
367 | * |
368 | * Read the byte at physical address paddr. Memory should not be cache inhibited. | |
369 | */ | |
370 | ||
371 | ; Force a line boundry here | |
55e303ae | 372 | |
1c79356b | 373 | .align 5 |
55e303ae A |
374 | .globl EXT(ml_phys_read_byte_64) |
375 | ||
376 | LEXT(ml_phys_read_byte_64) | |
377 | ||
378 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
379 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
380 | b ml_phys_read_byte_join | |
381 | ||
1c79356b A |
382 | .globl EXT(ml_phys_read_byte) |
383 | ||
384 | LEXT(ml_phys_read_byte) | |
55e303ae A |
385 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits |
386 | ml_phys_read_byte_join: ; r3 = address to read (reg64_t) | |
387 | mflr r11 ; Save the return | |
388 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
389 | ||
390 | lbz r3,0(r3) ; Get the byte | |
391 | b rdwrpost ; Clean up and leave... | |
d7e50217 | 392 | |
d7e50217 | 393 | |
55e303ae A |
394 | /* Read physical address half word |
395 | * | |
396 | * unsigned int ml_phys_read_half(vm_offset_t paddr) | |
397 | * unsigned int ml_phys_read_half_64(addr64_t paddr) | |
398 | * | |
399 | * Read the half word at physical address paddr. Memory should not be cache inhibited. | |
400 | */ | |
1c79356b | 401 | |
55e303ae | 402 | ; Force a line boundry here |
d7e50217 | 403 | |
55e303ae A |
404 | .align 5 |
405 | .globl EXT(ml_phys_read_half_64) | |
406 | ||
407 | LEXT(ml_phys_read_half_64) | |
408 | ||
409 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
410 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
411 | b ml_phys_read_half_join | |
d7e50217 | 412 | |
55e303ae A |
413 | .globl EXT(ml_phys_read_half) |
414 | ||
415 | LEXT(ml_phys_read_half) | |
416 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
417 | ml_phys_read_half_join: ; r3 = address to read (reg64_t) | |
418 | mflr r11 ; Save the return | |
419 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
420 | ||
421 | lhz r3,0(r3) ; Get the half word | |
422 | b rdwrpost ; Clean up and leave... | |
423 | ||
424 | ||
425 | /* Read physical address word | |
1c79356b A |
426 | * |
427 | * unsigned int ml_phys_read(vm_offset_t paddr) | |
55e303ae A |
428 | * unsigned int ml_phys_read_64(addr64_t paddr) |
429 | * unsigned int ml_phys_read_word(vm_offset_t paddr) | |
430 | * unsigned int ml_phys_read_word_64(addr64_t paddr) | |
1c79356b A |
431 | * |
432 | * Read the word at physical address paddr. Memory should not be cache inhibited. | |
433 | */ | |
434 | ||
435 | ; Force a line boundry here | |
55e303ae | 436 | |
1c79356b | 437 | .align 5 |
55e303ae A |
438 | .globl EXT(ml_phys_read_64) |
439 | .globl EXT(ml_phys_read_word_64) | |
440 | ||
441 | LEXT(ml_phys_read_64) | |
442 | LEXT(ml_phys_read_word_64) | |
443 | ||
444 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
445 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
446 | b ml_phys_read_word_join | |
447 | ||
1c79356b | 448 | .globl EXT(ml_phys_read) |
55e303ae | 449 | .globl EXT(ml_phys_read_word) |
1c79356b A |
450 | |
451 | LEXT(ml_phys_read) | |
55e303ae A |
452 | LEXT(ml_phys_read_word) |
453 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
454 | ml_phys_read_word_join: ; r3 = address to read (reg64_t) | |
455 | mflr r11 ; Save the return | |
456 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
457 | ||
458 | lwz r3,0(r3) ; Get the word | |
459 | b rdwrpost ; Clean up and leave... | |
d7e50217 | 460 | |
d7e50217 | 461 | |
55e303ae A |
462 | /* Read physical address double word |
463 | * | |
464 | * unsigned long long ml_phys_read_double(vm_offset_t paddr) | |
465 | * unsigned long long ml_phys_read_double_64(addr64_t paddr) | |
466 | * | |
467 | * Read the double word at physical address paddr. Memory should not be cache inhibited. | |
468 | */ | |
469 | ||
470 | ; Force a line boundry here | |
471 | ||
472 | .align 5 | |
473 | .globl EXT(ml_phys_read_double_64) | |
474 | ||
475 | LEXT(ml_phys_read_double_64) | |
476 | ||
477 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
478 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
479 | b ml_phys_read_double_join | |
480 | ||
481 | .globl EXT(ml_phys_read_double) | |
482 | ||
483 | LEXT(ml_phys_read_double) | |
484 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
485 | ml_phys_read_double_join: ; r3 = address to read (reg64_t) | |
486 | mflr r11 ; Save the return | |
487 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
1c79356b | 488 | |
55e303ae A |
489 | lwz r4,4(r3) ; Get the low word |
490 | lwz r3,0(r3) ; Get the high word | |
491 | b rdwrpost ; Clean up and leave... | |
1c79356b | 492 | |
1c79356b A |
493 | |
494 | /* Write physical address byte | |
495 | * | |
496 | * void ml_phys_write_byte(vm_offset_t paddr, unsigned int data) | |
55e303ae | 497 | * void ml_phys_write_byte_64(addr64_t paddr, unsigned int data) |
1c79356b A |
498 | * |
499 | * Write the byte at physical address paddr. Memory should not be cache inhibited. | |
500 | */ | |
501 | ||
1c79356b | 502 | .align 5 |
55e303ae A |
503 | .globl EXT(ml_phys_write_byte_64) |
504 | ||
505 | LEXT(ml_phys_write_byte_64) | |
506 | ||
507 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
508 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
509 | mr r4,r5 ; Copy over the data | |
510 | b ml_phys_write_byte_join | |
511 | ||
1c79356b A |
512 | .globl EXT(ml_phys_write_byte) |
513 | ||
514 | LEXT(ml_phys_write_byte) | |
55e303ae A |
515 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits |
516 | ml_phys_write_byte_join: ; r3 = address to write (reg64_t), r4 = data | |
517 | mflr r11 ; Save the return | |
518 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
519 | ||
520 | stb r4,0(r3) ; Set the byte | |
521 | b rdwrpost ; Clean up and leave... | |
1c79356b | 522 | |
d7e50217 | 523 | |
55e303ae A |
524 | /* Write physical address half word |
525 | * | |
526 | * void ml_phys_write_half(vm_offset_t paddr, unsigned int data) | |
527 | * void ml_phys_write_half_64(addr64_t paddr, unsigned int data) | |
528 | * | |
529 | * Write the half word at physical address paddr. Memory should not be cache inhibited. | |
530 | */ | |
531 | ||
532 | .align 5 | |
533 | .globl EXT(ml_phys_write_half_64) | |
534 | ||
535 | LEXT(ml_phys_write_half_64) | |
536 | ||
537 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
538 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
539 | mr r4,r5 ; Copy over the data | |
540 | b ml_phys_write_half_join | |
541 | ||
542 | .globl EXT(ml_phys_write_half) | |
543 | ||
544 | LEXT(ml_phys_write_half) | |
545 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
546 | ml_phys_write_half_join: ; r3 = address to write (reg64_t), r4 = data | |
547 | mflr r11 ; Save the return | |
548 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
1c79356b | 549 | |
55e303ae A |
550 | sth r4,0(r3) ; Set the half word |
551 | b rdwrpost ; Clean up and leave... | |
1c79356b | 552 | |
1c79356b | 553 | |
55e303ae | 554 | /* Write physical address word |
1c79356b A |
555 | * |
556 | * void ml_phys_write(vm_offset_t paddr, unsigned int data) | |
55e303ae A |
557 | * void ml_phys_write_64(addr64_t paddr, unsigned int data) |
558 | * void ml_phys_write_word(vm_offset_t paddr, unsigned int data) | |
559 | * void ml_phys_write_word_64(addr64_t paddr, unsigned int data) | |
1c79356b A |
560 | * |
561 | * Write the word at physical address paddr. Memory should not be cache inhibited. | |
562 | */ | |
563 | ||
1c79356b | 564 | .align 5 |
55e303ae A |
565 | .globl EXT(ml_phys_write_64) |
566 | .globl EXT(ml_phys_write_word_64) | |
567 | ||
568 | LEXT(ml_phys_write_64) | |
569 | LEXT(ml_phys_write_word_64) | |
570 | ||
571 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
572 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
573 | mr r4,r5 ; Copy over the data | |
574 | b ml_phys_write_word_join | |
575 | ||
1c79356b | 576 | .globl EXT(ml_phys_write) |
55e303ae | 577 | .globl EXT(ml_phys_write_word) |
1c79356b A |
578 | |
579 | LEXT(ml_phys_write) | |
55e303ae A |
580 | LEXT(ml_phys_write_word) |
581 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
582 | ml_phys_write_word_join: ; r3 = address to write (reg64_t), r4 = data | |
583 | mflr r11 ; Save the return | |
584 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
585 | ||
586 | stw r4,0(r3) ; Set the word | |
587 | b rdwrpost ; Clean up and leave... | |
d7e50217 | 588 | |
d7e50217 | 589 | |
55e303ae A |
590 | /* Write physical address double word |
591 | * | |
592 | * void ml_phys_write_double(vm_offset_t paddr, unsigned long long data) | |
593 | * void ml_phys_write_double_64(addr64_t paddr, unsigned long long data) | |
594 | * | |
595 | * Write the double word at physical address paddr. Memory should not be cache inhibited. | |
596 | */ | |
597 | ||
598 | .align 5 | |
599 | .globl EXT(ml_phys_write_double_64) | |
600 | ||
601 | LEXT(ml_phys_write_double_64) | |
602 | ||
603 | rlwinm r3,r3,0,1,0 ; Copy low 32 bits to top 32 | |
604 | rlwimi r3,r4,0,0,31 ; Insert low part of 64-bit address in bottom 32 bits | |
605 | mr r4,r5 ; Copy over the high data | |
606 | mr r5,r6 ; Copy over the low data | |
607 | b ml_phys_write_double_join | |
608 | ||
609 | .globl EXT(ml_phys_write_double) | |
610 | ||
611 | LEXT(ml_phys_write_double) | |
612 | rlwinm r3,r3,0,0,31 ; truncate address to 32-bits | |
613 | ml_phys_write_double_join: ; r3 = address to write (reg64_t), r4,r5 = data (long long) | |
614 | mflr r11 ; Save the return | |
615 | bl rdwrpre ; Get set up, translation/interrupts off, 64-bit on, etc. | |
616 | ||
617 | stw r4,0(r3) ; Set the high word | |
618 | stw r5,4(r3) ; Set the low word | |
619 | b rdwrpost ; Clean up and leave... | |
620 | ||
621 | ||
622 | .align 5 | |
623 | ||
624 | rdwrpre: mfsprg r12,2 ; Get feature flags | |
625 | lis r8,hi16(MASK(MSR_VEC)) ; Get the vector flag | |
626 | mfmsr r10 ; Save the MSR | |
627 | ori r8,r8,lo16(MASK(MSR_FP)) ; Add the FP flag | |
628 | mtcrf 0x02,r12 ; move pf64Bit | |
629 | andc r10,r10,r8 ; Clear VEC and FP | |
630 | ori r9,r8,lo16(MASK(MSR_EE)|MASK(MSR_IR)|MASK(MSR_DR)) ; Drop EE, DR, and IR | |
631 | li r2,1 ; Prepare for 64 bit | |
632 | andc r9,r10,r9 ; Clear VEC, FP, DR, and EE | |
633 | bf-- pf64Bitb,rdwrpre32 ; Join 32-bit code... | |
634 | ||
635 | srdi r7,r3,31 ; Get a 1 if address is in I/O memory | |
636 | rldimi r9,r2,63,MSR_SF_BIT ; set SF bit (bit 0) | |
637 | cmpldi cr7,r7,1 ; Is source in I/O memory? | |
638 | mtmsrd r9 ; set 64-bit mode, turn off EE, DR, and IR | |
639 | isync ; synchronize | |
640 | ||
641 | sldi r0,r2,32+8 ; Get the right bit to turn off caching | |
642 | ||
643 | bnelr++ cr7 ; We are not in the I/O area, all ready... | |
644 | ||
645 | mfspr r8,hid4 ; Get HID4 | |
646 | or r2,r8,r0 ; Set bit to make real accesses cache-inhibited | |
647 | sync ; Sync up | |
648 | mtspr hid4,r2 ; Make real accesses cache-inhibited | |
649 | isync ; Toss prefetches | |
650 | ||
651 | lis r7,0xE000 ; Get the unlikeliest ESID possible | |
652 | srdi r7,r7,1 ; Make 0x7FFFFFFFF0000000 | |
653 | slbie r7 ; Make sure the ERAT is cleared | |
1c79356b | 654 | |
1c79356b | 655 | sync |
55e303ae A |
656 | isync |
657 | blr ; Finally, all ready... | |
658 | ||
659 | .align 5 | |
660 | ||
661 | rdwrpre32: rlwimi r9,r10,0,MSR_IR_BIT,MSR_IR_BIT ; Leave the IR bit unchanged | |
662 | mtmsr r9 ; Drop EE, DR, and leave IR unchanged | |
663 | isync | |
664 | blr ; All set up, leave... | |
665 | ||
666 | .align 5 | |
667 | ||
668 | rdwrpost: mtlr r11 ; Restore the return | |
669 | bt++ pf64Bitb,rdwrpost64 ; Join 64-bit code... | |
670 | ||
671 | mtmsr r10 ; Restore entry MSR (sans FP and VEC) | |
672 | isync | |
673 | blr ; Leave... | |
674 | ||
675 | rdwrpost64: bne++ cr7,rdwrpcok ; Skip enabling real mode caching if we did not change it... | |
1c79356b | 676 | |
55e303ae A |
677 | sync ; Sync up |
678 | mtspr hid4,r8 ; Make real accesses not cache-inhibited | |
679 | isync ; Toss prefetches | |
680 | ||
681 | lis r7,0xE000 ; Get the unlikeliest ESID possible | |
682 | srdi r7,r7,1 ; Make 0x7FFFFFFFF0000000 | |
683 | slbie r7 ; Make sure the ERAT is cleared | |
684 | ||
685 | rdwrpcok: mtmsrd r10 ; Restore entry MSR (sans FP and VEC) | |
1c79356b | 686 | isync |
55e303ae | 687 | blr ; Leave... |
1c79356b A |
688 | |
689 | ||
690 | /* set interrupts enabled or disabled | |
691 | * | |
692 | * boolean_t set_interrupts_enabled(boolean_t enable) | |
693 | * | |
694 | * Set EE bit to "enable" and return old value as boolean | |
695 | */ | |
696 | ||
697 | ; Force a line boundry here | |
0b4e3aa0 A |
698 | .align 5 |
699 | .globl EXT(ml_set_interrupts_enabled) | |
700 | ||
701 | LEXT(ml_set_interrupts_enabled) | |
1c79356b | 702 | |
55e303ae A |
703 | andi. r4,r3,1 ; Are we turning interruptions on? |
704 | lis r0,hi16(MASK(MSR_VEC)) ; Get vector enable | |
1c79356b | 705 | mfmsr r5 ; Get the current MSR |
55e303ae | 706 | ori r0,r0,lo16(MASK(MSR_EE)|MASK(MSR_FP)) ; Get float enable and EE enable |
1c79356b | 707 | rlwinm r3,r5,17,31,31 ; Set return value |
55e303ae A |
708 | andc r5,r5,r0 ; Force VEC and FP off |
709 | bne CheckPreemption ; Interrupts going on, check ASTs... | |
710 | ||
711 | mtmsr r5 ; Slam diable (always going disabled here) | |
712 | isync ; Need this because FP/Vec might go off | |
1c79356b A |
713 | blr |
714 | ||
55e303ae A |
715 | .align 5 |
716 | ||
d7e50217 | 717 | CheckPreemption: |
55e303ae | 718 | mfsprg r9,1 ; Get current activation |
91447636 A |
719 | lwz r7,ACT_PER_PROC(r9) ; Get the per_proc block |
720 | ori r5,r5,lo16(MASK(MSR_EE)) ; Turn on the enable | |
721 | lwz r8,PP_PENDING_AST(r7) ; Get pending AST mask | |
55e303ae A |
722 | li r6,AST_URGENT ; Get the type we will preempt for |
723 | lwz r7,ACT_PREEMPT_CNT(r9) ; Get preemption count | |
55e303ae A |
724 | lis r0,hi16(DoPreemptCall) ; High part of Preempt FW call |
725 | cmpwi cr1,r7,0 ; Are preemptions masked off? | |
726 | and. r8,r8,r6 ; Are we urgent? | |
727 | crorc cr1_eq,cr0_eq,cr1_eq ; Remember if preemptions are masked or not urgent | |
728 | ori r0,r0,lo16(DoPreemptCall) ; Bottome of FW call | |
729 | ||
d7e50217 | 730 | mtmsr r5 ; Restore the MSR now, before we can preempt |
55e303ae A |
731 | isync ; Need this because FP/Vec might go off |
732 | ||
733 | beqlr++ cr1 ; Return if no premption... | |
d7e50217 | 734 | sc ; Preempt |
0b4e3aa0 A |
735 | blr |
736 | ||
91447636 A |
737 | ; Force a line boundry here |
738 | .align 5 | |
739 | .globl EXT(timer_update) | |
740 | ||
741 | LEXT(timer_update) | |
742 | stw r4,TIMER_HIGHCHK(r3) | |
743 | eieio | |
744 | stw r5,TIMER_LOW(r3) | |
745 | eieio | |
746 | stw r4,TIMER_HIGH(r3) | |
747 | blr | |
de355530 A |
748 | |
749 | ; Force a line boundry here | |
750 | .align 5 | |
91447636 | 751 | .globl EXT(timer_grab) |
de355530 | 752 | |
91447636 A |
753 | LEXT(timer_grab) |
754 | 0: lwz r11,TIMER_HIGH(r3) | |
755 | lwz r4,TIMER_LOW(r3) | |
756 | isync | |
757 | lwz r9,TIMER_HIGHCHK(r3) | |
758 | cmpw r11,r9 | |
759 | bne-- 0b | |
760 | mr r3,r11 | |
761 | blr | |
de355530 | 762 | |
91447636 A |
763 | ; Force a line boundry here |
764 | .align 5 | |
2d21ac55 A |
765 | .globl EXT(thread_timer_event) |
766 | ||
767 | LEXT(thread_timer_event) | |
768 | mfsprg r10,1 ; Get the current activation | |
769 | lwz r10,ACT_PER_PROC(r10) ; Get the per_proc block | |
770 | addi r10,r10,PP_PROCESSOR | |
771 | lwz r11,THREAD_TIMER(r10) | |
772 | ||
773 | lwz r9,TIMER_LOW(r11) | |
774 | lwz r7,TIMER_TSTAMP(r11) | |
775 | lwz r8,TIMER_TSTAMP+4(r11) | |
776 | subfc r8,r8,r4 | |
777 | subfe r7,r7,r3 | |
778 | addc r8,r8,r9 | |
779 | addze. r7,r7 | |
780 | beq++ 0f | |
781 | ||
782 | lwz r6,TIMER_HIGH(r11) | |
783 | add r7,r7,r6 | |
784 | stw r7,TIMER_HIGHCHK(r11) | |
785 | eieio | |
786 | stw r8,TIMER_LOW(r11) | |
787 | eieio | |
788 | stw r7,TIMER_HIGH(r11) | |
789 | b 1f | |
790 | ||
791 | 0: stw r8,TIMER_LOW(r11) | |
792 | ||
793 | 1: stw r5,THREAD_TIMER(r10) | |
794 | stw r3,TIMER_TSTAMP(r5) | |
795 | stw r4,TIMER_TSTAMP+4(r5) | |
796 | blr | |
797 | ||
798 | ; Force a line boundry here | |
799 | .align 5 | |
800 | .globl EXT(state_event) | |
91447636 | 801 | |
2d21ac55 | 802 | LEXT(state_event) |
91447636 A |
803 | mfsprg r10,1 ; Get the current activation |
804 | lwz r10,ACT_PER_PROC(r10) ; Get the per_proc block | |
805 | addi r10,r10,PP_PROCESSOR | |
2d21ac55 | 806 | lwz r11,CURRENT_STATE(r10) |
91447636 A |
807 | |
808 | lwz r9,TIMER_LOW(r11) | |
2d21ac55 A |
809 | lwz r7,TIMER_TSTAMP(r11) |
810 | lwz r8,TIMER_TSTAMP+4(r11) | |
811 | subfc r8,r8,r4 | |
812 | subfe r7,r7,r3 | |
813 | addc r8,r8,r9 | |
814 | addze. r7,r7 | |
815 | beq++ 0f | |
91447636 A |
816 | |
817 | lwz r6,TIMER_HIGH(r11) | |
2d21ac55 A |
818 | add r7,r7,r6 |
819 | stw r7,TIMER_HIGHCHK(r11) | |
91447636 | 820 | eieio |
2d21ac55 | 821 | stw r8,TIMER_LOW(r11) |
91447636 | 822 | eieio |
2d21ac55 | 823 | stw r7,TIMER_HIGH(r11) |
91447636 A |
824 | b 1f |
825 | ||
2d21ac55 | 826 | 0: stw r8,TIMER_LOW(r11) |
91447636 | 827 | |
2d21ac55 A |
828 | 1: stw r5,CURRENT_STATE(r10) |
829 | stw r3,TIMER_TSTAMP(r5) | |
830 | stw r4,TIMER_TSTAMP+4(r5) | |
91447636 | 831 | blr |
de355530 | 832 | |
1c79356b A |
833 | /* Set machine into idle power-saving mode. |
834 | * | |
91447636 | 835 | * void machine_idle(void) |
1c79356b A |
836 | * |
837 | * We will use the PPC NAP or DOZE for this. | |
838 | * This call always returns. Must be called with spllo (i.e., interruptions | |
839 | * enabled). | |
840 | * | |
841 | */ | |
842 | ||
1c79356b A |
843 | ; Force a line boundry here |
844 | .align 5 | |
91447636 | 845 | .globl EXT(machine_idle) |
1c79356b | 846 | |
91447636 | 847 | LEXT(machine_idle) |
1c79356b | 848 | |
91447636 A |
849 | mfsprg r12,1 ; Get the current activation |
850 | lwz r12,ACT_PER_PROC(r12) ; Get the per_proc block | |
851 | lhz r10,PP_CPU_FLAGS(r12) ; Get the flags | |
852 | lwz r11,PP_INTS_ENABLED(r12) ; Get interrupt enabled state | |
853 | andi. r10,r10,SignalReady ; Are Signal ready? | |
854 | cmpwi cr1,r11,0 ; Are interrupt disabled? | |
855 | cror cr0_eq, cr1_eq, cr0_eq ; Interrupt disabled or Signal not ready? | |
55e303ae | 856 | mfmsr r3 ; Save the MSR |
91447636 A |
857 | |
858 | beq-- nonap ; Yes, return after re-enabling interrupts | |
859 | lis r0,hi16(MASK(MSR_VEC)) ; Get the vector flag | |
55e303ae A |
860 | ori r0,r0,lo16(MASK(MSR_FP)) ; Add the FP flag |
861 | andc r3,r3,r0 ; Clear VEC and FP | |
862 | ori r0,r0,lo16(MASK(MSR_EE)) ; Drop EE also | |
863 | andc r5,r3,r0 ; Clear VEC, FP, DR, and EE | |
864 | ||
1c79356b | 865 | mtmsr r5 ; Hold up interruptions for now |
9bccf70c | 866 | isync ; May have messed with fp/vec |
de355530 | 867 | mfsprg r11,2 ; Get CPU specific features |
55e303ae | 868 | mfspr r6,hid0 ; Get the current power-saving mode |
1c79356b A |
869 | mtcrf 0xC7,r11 ; Get the facility flags |
870 | ||
871 | lis r4,hi16(napm) ; Assume we can nap | |
872 | bt pfWillNapb,yesnap ; Yeah, nap is ok... | |
873 | ||
874 | lis r4,hi16(dozem) ; Assume we can doze | |
875 | bt pfCanDozeb,yesnap ; We can sleep or doze one this machine... | |
5353443c | 876 | |
91447636 | 877 | nonap: ori r3,r3,lo16(MASK(MSR_EE)) ; Flip on EE |
5353443c | 878 | |
1c79356b A |
879 | mtmsr r3 ; Turn interruptions back on |
880 | blr ; Leave... | |
881 | ||
882 | yesnap: mftbu r9 ; Get the upper timebase | |
883 | mftb r7 ; Get the lower timebase | |
884 | mftbu r8 ; Get the upper one again | |
885 | cmplw r9,r8 ; Did the top tick? | |
5353443c | 886 | bne-- yesnap ; Yeah, need to get it again... |
1c79356b A |
887 | stw r8,napStamp(r12) ; Set high order time stamp |
888 | stw r7,napStamp+4(r12) ; Set low order nap stamp | |
d52fe63f | 889 | |
5eebf738 | 890 | rlwinm. r0,r11,0,pfAltivecb,pfAltivecb ; Do we have altivec? |
91447636 | 891 | beq-- minovec ; No... |
5eebf738 A |
892 | dssall ; Stop the streams before we nap/doze |
893 | sync | |
894 | lwz r8,napStamp(r12) ; Reload high order time stamp | |
895 | clearpipe: | |
896 | cmplw r8,r8 | |
5353443c | 897 | bne- clearpipe |
5eebf738 | 898 | isync |
5eebf738 | 899 | |
91447636 A |
900 | minovec: rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap? |
901 | beq++ miL2PFok | |
9bccf70c A |
902 | |
903 | mfspr r7,msscr0 ; Get currect MSSCR0 value | |
55e303ae | 904 | rlwinm r7,r7,0,0,l2pfes-1 ; Disable L2 Prefetch |
9bccf70c A |
905 | mtspr msscr0,r7 ; Updates MSSCR0 value |
906 | sync | |
907 | isync | |
908 | ||
91447636 A |
909 | miL2PFok: |
910 | rlwinm. r7,r11,0,pfSlowNapb,pfSlowNapb ; Should nap at slow speed? | |
911 | beq minoslownap | |
9bccf70c A |
912 | |
913 | mfspr r7,hid1 ; Get current HID1 value | |
55e303ae | 914 | oris r7,r7,hi16(hid1psm) ; Select PLL1 |
9bccf70c A |
915 | mtspr hid1,r7 ; Update HID1 value |
916 | ||
d52fe63f | 917 | |
1c79356b A |
918 | ; |
919 | ; We have to open up interruptions here because book 4 says that we should | |
5353443c | 920 | ; turn on only the POW bit and that we should have interrupts enabled. |
1c79356b A |
921 | ; The interrupt handler will detect that nap or doze is set if an interrupt |
922 | ; is taken and set everything up to return directly to machine_idle_ret. | |
923 | ; So, make sure everything we need there is already set up... | |
924 | ; | |
55e303ae | 925 | |
5353443c | 926 | minoslownap: |
ab86ba33 | 927 | lis r10,hi16(dozem|napm|sleepm) ; Mask of power management bits |
55e303ae A |
928 | |
929 | bf-- pf64Bitb,mipNSF1 ; skip if 32-bit... | |
930 | ||
931 | sldi r4,r4,32 ; Position the flags | |
932 | sldi r10,r10,32 ; Position the masks | |
933 | ||
5353443c A |
934 | mipNSF1: li r2,lo16(MASK(MSR_DR)|MASK(MSR_IR)) ; Get the translation mask |
935 | andc r6,r6,r10 ; Clean up the old power bits | |
936 | ori r7,r5,lo16(MASK(MSR_EE)) ; Flip on EE to make exit msr | |
937 | andc r5,r5,r2 ; Clear IR and DR from current MSR | |
1c79356b | 938 | or r6,r6,r4 ; Set nap or doze |
5353443c A |
939 | ori r5,r5,lo16(MASK(MSR_EE)) ; Flip on EE to make nap msr |
940 | oris r2,r5,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR | |
55e303ae A |
941 | |
942 | sync | |
1c79356b | 943 | mtspr hid0,r6 ; Set up the HID for nap/doze |
55e303ae A |
944 | mfspr r6,hid0 ; Yes, this is silly, keep it here |
945 | mfspr r6,hid0 ; Yes, this is a duplicate, keep it here | |
946 | mfspr r6,hid0 ; Yes, this is a duplicate, keep it here | |
947 | mfspr r6,hid0 ; Yes, this is a duplicate, keep it here | |
948 | mfspr r6,hid0 ; Yes, this is a duplicate, keep it here | |
949 | mfspr r6,hid0 ; Yes, this is a duplicate, keep it here | |
1c79356b | 950 | isync ; Make sure it is set |
1c79356b | 951 | |
91447636 | 952 | |
5353443c A |
953 | ; |
954 | ; Turn translation off to nap | |
955 | ; | |
956 | ||
957 | bt pfNoMSRirb,miNoMSR ; Jump if we need to use SC for this... | |
958 | mtmsr r5 ; Turn translation off, interrupts on | |
959 | isync ; Wait for it | |
960 | b miNoMSRx ; Jump back in line... | |
4a249263 | 961 | |
5353443c A |
962 | miNoMSR: mr r3,r5 ; Pass in the new MSR value |
963 | li r0,loadMSR ; MSR setter ultrafast | |
964 | sc ; Do it to it like you never done before... | |
965 | ||
966 | miNoMSRx: bf-- pf64Bitb,mipowloop ; skip if 32-bit... | |
967 | ||
968 | li r3,0x10 ; Fancy nap threshold is 0x10 ticks | |
4a249263 A |
969 | mftb r8 ; Get the low half of the time base |
970 | mfdec r4 ; Get the decrementer ticks | |
5353443c | 971 | cmplw r4,r3 ; Less than threshold? |
4a249263 A |
972 | blt mipowloop |
973 | ||
5353443c | 974 | mtdec r3 ; Load decrementer with threshold |
4a249263 A |
975 | isync ; and make sure, |
976 | mfdec r3 ; really sure, it gets there | |
977 | ||
5353443c | 978 | rlwinm r6,r2,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear out the EE bit |
4a249263 A |
979 | sync ; Make sure queues are clear |
980 | mtmsr r6 ; Set MSR with EE off but POW on | |
1c79356b | 981 | isync ; Make sure this takes before we proceed |
4a249263 A |
982 | |
983 | mftb r9 ; Get the low half of the time base | |
984 | sub r9,r9,r8 ; Get the number of ticks spent waiting | |
985 | sub r4,r4,r9 ; Adjust the decrementer value | |
986 | ||
5353443c | 987 | mtdec r4 ; Load decrementer with the rest of the timeout |
4a249263 A |
988 | isync ; and make sure, |
989 | mfdec r4 ; really sure, it gets there | |
990 | ||
991 | mipowloop: | |
992 | sync ; Make sure queues are clear | |
5353443c | 993 | mtmsr r2 ; Nap or doze, MSR with POW, EE set, translation off |
4a249263 A |
994 | isync ; Make sure this takes before we proceed |
995 | b mipowloop ; loop if POW does not take | |
996 | ||
1c79356b A |
997 | ; |
998 | ; Note that the interrupt handler will turn off the nap/doze bits in the hid. | |
999 | ; Also remember that the interrupt handler will force return to here whenever | |
1000 | ; the nap/doze bits are set. | |
1001 | ; | |
1002 | .globl EXT(machine_idle_ret) | |
1003 | LEXT(machine_idle_ret) | |
1004 | mtmsr r7 ; Make sure the MSR is what we want | |
1005 | isync ; In case we turn on translation | |
91447636 A |
1006 | ; |
1007 | ; Protect against a lost decrementer trap if the current decrementer value is negative | |
1008 | ; by more than 10 ticks, re-arm it since it is unlikely to fire at this point... | |
1009 | ; A hardware interrupt got us out of machine_idle and may also be contributing to this state | |
1010 | ; | |
1011 | mfdec r6 ; Get decrementer | |
1012 | cmpwi cr0,r6,-10 ; Compare decrementer with -10 | |
1013 | bgelr++ ; Return if greater | |
1014 | li r0,1 ; Load 1 | |
1015 | mtdec r0 ; Set decrementer to 1 | |
1c79356b A |
1016 | blr ; Return... |
1017 | ||
1018 | /* Put machine to sleep. | |
1019 | * This call never returns. We always exit sleep via a soft reset. | |
1020 | * All external interruptions must be drained at this point and disabled. | |
1021 | * | |
91447636 | 1022 | * void ml_ppc_do_sleep(void) |
1c79356b A |
1023 | * |
1024 | * We will use the PPC SLEEP for this. | |
1025 | * | |
1026 | * There is one bit of hackery in here: we need to enable for | |
1027 | * interruptions when we go to sleep and there may be a pending | |
91447636 A |
1028 | * decrimenter rupt. So we make the decrimenter 0x7FFFFFFF and enable for |
1029 | * interruptions. The decrimenter rupt vector recognizes this and returns | |
1c79356b A |
1030 | * directly back here. |
1031 | * | |
1032 | */ | |
1033 | ||
1034 | ; Force a line boundry here | |
1035 | .align 5 | |
91447636 | 1036 | .globl EXT(ml_ppc_do_sleep) |
3a60a9f5 | 1037 | |
91447636 A |
1038 | LEXT(ml_ppc_do_sleep) |
1039 | ||
1c79356b A |
1040 | #if 0 |
1041 | mfmsr r5 ; Hack to spin instead of sleep | |
1042 | rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation | |
1043 | rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions | |
1044 | mtmsr r5 ; No talking | |
1045 | isync | |
1046 | ||
1c79356b A |
1047 | deadsleep: addi r3,r3,1 ; Make analyzer happy |
1048 | addi r3,r3,1 | |
1049 | addi r3,r3,1 | |
1050 | b deadsleep ; Die the death of 1000 joys... | |
1051 | #endif | |
1052 | ||
91447636 A |
1053 | mfsprg r12,1 ; Get the current activation |
1054 | lwz r12,ACT_PER_PROC(r12) ; Get the per_proc block | |
1c79356b | 1055 | mfsprg r11,2 ; Get CPU specific features |
91447636 A |
1056 | eqv r10,r10,r10 ; Get all foxes |
1057 | mtcrf 0x04,r11 ; move pfNoMSRirb to cr5 | |
1058 | mfspr r4,hid0 ; Get the current power-saving mode | |
1059 | mtcrf 0x02,r11 ; move pf64Bit to cr6 | |
9bccf70c | 1060 | |
55e303ae | 1061 | rlwinm. r5,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before sleep? |
9bccf70c A |
1062 | beq mpsL2PFok |
1063 | ||
1064 | mfspr r5,msscr0 ; Get currect MSSCR0 value | |
55e303ae | 1065 | rlwinm r5,r5,0,0,l2pfes-1 ; Disable L2 Prefetch |
9bccf70c A |
1066 | mtspr msscr0,r5 ; Updates MSSCR0 value |
1067 | sync | |
1068 | isync | |
1069 | ||
1070 | mpsL2PFok: | |
91447636 | 1071 | bt++ pf64Bitb,mpsPF64bit ; PM bits are shifted on 64bit systems. |
55e303ae A |
1072 | |
1073 | rlwinm r4,r4,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though) | |
1074 | oris r4,r4,hi16(sleepm) ; Set sleep | |
4a249263 | 1075 | b mpsClearDEC |
55e303ae A |
1076 | |
1077 | mpsPF64bit: | |
4a249263 | 1078 | lis r5, hi16(dozem|napm|sleepm) ; Clear all possible power-saving modes (not DPM though) |
55e303ae A |
1079 | sldi r5, r5, 32 |
1080 | andc r4, r4, r5 | |
4a249263 | 1081 | lis r5, hi16(napm) ; Set sleep |
55e303ae | 1082 | sldi r5, r5, 32 |
4a249263 | 1083 | or r4, r4, r5 |
55e303ae A |
1084 | |
1085 | mpsClearDEC: | |
1c79356b A |
1086 | mfmsr r5 ; Get the current MSR |
1087 | rlwinm r10,r10,0,1,31 ; Make 0x7FFFFFFF | |
91447636 | 1088 | mtdec r10 ; Load decrimenter with 0x7FFFFFFF |
1c79356b A |
1089 | isync ; and make sure, |
1090 | mfdec r9 ; really sure, it gets there | |
1091 | ||
91447636 | 1092 | li r2,1 ; Prepare for 64 bit |
1c79356b A |
1093 | rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation |
1094 | ; | |
1095 | ; Note that we need translation off before we set the HID to sleep. Otherwise | |
1096 | ; we will ignore any PTE misses that occur and cause an infinite loop. | |
1097 | ; | |
91447636 A |
1098 | bf++ pf64Bitb,mpsCheckMSR ; check 64-bit processor |
1099 | rldimi r5,r2,63,MSR_SF_BIT ; set SF bit (bit 0) | |
1100 | mtmsrd r5 ; set 64-bit mode, turn off EE, DR, and IR | |
1101 | isync ; Toss prefetch | |
1102 | b mpsNoMSRx | |
1103 | ||
1104 | mpsCheckMSR: | |
1c79356b A |
1105 | bt pfNoMSRirb,mpsNoMSR ; No MSR... |
1106 | ||
1107 | mtmsr r5 ; Translation off | |
1108 | isync ; Toss prefetch | |
1109 | b mpsNoMSRx | |
1110 | ||
1111 | mpsNoMSR: | |
1112 | li r0,loadMSR ; Get the MSR setter SC | |
1113 | mr r3,r5 ; Get new MSR | |
1114 | sc ; Set it | |
1115 | mpsNoMSRx: | |
1116 | ||
1117 | ori r3,r5,lo16(MASK(MSR_EE)) ; Flip on EE | |
1118 | sync | |
1119 | mtspr hid0,r4 ; Set up the HID to sleep | |
55e303ae A |
1120 | mfspr r4,hid0 ; Yes, this is silly, keep it here |
1121 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1122 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1123 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1124 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1125 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1c79356b | 1126 | |
91447636 | 1127 | mtmsr r3 ; Enable for interrupts to drain decrimenter |
1c79356b A |
1128 | |
1129 | add r6,r4,r5 ; Just waste time | |
1130 | add r6,r6,r4 ; A bit more | |
1131 | add r6,r6,r5 ; A bit more | |
1132 | ||
1133 | mtmsr r5 ; Interruptions back off | |
1134 | isync ; Toss prefetch | |
1135 | ||
1c79356b A |
1136 | ; |
1137 | ; We are here with translation off, interrupts off, all possible | |
91447636 | 1138 | ; interruptions drained off, and a decrimenter that will not pop. |
1c79356b A |
1139 | ; |
1140 | ||
1141 | bl EXT(cacheInit) ; Clear out the caches. This will leave them on | |
1142 | bl EXT(cacheDisable) ; Turn off all caches | |
1143 | ||
1144 | mfmsr r5 ; Get the current MSR | |
1145 | oris r5,r5,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR | |
1146 | ; Leave EE off because power goes off shortly | |
55e303ae A |
1147 | mfsprg r12,0 ; Get the per_proc_info |
1148 | li r10,PP_CPU_FLAGS | |
1149 | lhz r11,PP_CPU_FLAGS(r12) ; Get the flags | |
1150 | ori r11,r11,SleepState ; Marked SleepState | |
1151 | sth r11,PP_CPU_FLAGS(r12) ; Set the flags | |
1152 | dcbf r10,r12 | |
4a249263 A |
1153 | |
1154 | mfsprg r11,2 ; Get CPU specific features | |
1155 | rlwinm. r0,r11,0,pf64Bitb,pf64Bitb ; Test for 64 bit processor | |
1156 | eqv r4,r4,r4 ; Get all foxes | |
1157 | rlwinm r4,r4,0,1,31 ; Make 0x7FFFFFFF | |
1158 | beq slSleepNow ; skip if 32-bit... | |
91447636 A |
1159 | li r3, 0x4000 ; Cause decrimenter to roll over soon |
1160 | mtdec r3 ; Load decrimenter with 0x00004000 | |
4a249263 A |
1161 | isync ; and make sure, |
1162 | mfdec r3 ; really sure, it gets there | |
1163 | ||
55e303ae A |
1164 | slSleepNow: |
1165 | sync ; Sync it all up | |
1c79356b A |
1166 | mtmsr r5 ; Do sleep with interruptions enabled |
1167 | isync ; Take a pill | |
91447636 | 1168 | mtdec r4 ; Load decrimenter with 0x7FFFFFFF |
4a249263 A |
1169 | isync ; and make sure, |
1170 | mfdec r3 ; really sure, it gets there | |
1c79356b A |
1171 | b slSleepNow ; Go back to sleep if we wake up... |
1172 | ||
1173 | ||
1174 | ||
1175 | /* Initialize all caches including the TLBs | |
1176 | * | |
1177 | * void cacheInit(void) | |
1178 | * | |
1179 | * This is used to force the caches to an initial clean state. First, we | |
1180 | * check if the cache is on, if so, we need to flush the contents to memory. | |
1181 | * Then we invalidate the L1. Next, we configure and invalidate the L2 etc. | |
1182 | * Finally we turn on all of the caches | |
1183 | * | |
1184 | * Note that if translation is not disabled when this is called, the TLB will not | |
1185 | * be completely clear after return. | |
1186 | * | |
1187 | */ | |
1188 | ||
1189 | ; Force a line boundry here | |
1190 | .align 5 | |
1191 | .globl EXT(cacheInit) | |
1192 | ||
1193 | LEXT(cacheInit) | |
1194 | ||
1195 | mfsprg r12,0 ; Get the per_proc_info | |
1196 | mfspr r9,hid0 ; Get the current power-saving mode | |
1197 | ||
1198 | mfsprg r11,2 ; Get CPU specific features | |
1199 | mfmsr r7 ; Get the current MSR | |
9bccf70c A |
1200 | rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off |
1201 | rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
0b4e3aa0 | 1202 | rlwimi r11,r11,pfLClckb+1,31,31 ; Move pfLClck to another position (to keep from using non-volatile CRs) |
1c79356b A |
1203 | rlwinm r5,r7,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation |
1204 | rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions | |
1205 | mtcrf 0x87,r11 ; Get the feature flags | |
55e303ae A |
1206 | lis r10,hi16(dozem|napm|sleepm|dpmm) ; Mask of power management bits |
1207 | bf-- pf64Bitb,cIniNSF1 ; Skip if 32-bit... | |
1208 | ||
1209 | sldi r10,r10,32 ; Position the masks | |
1210 | ||
1211 | cIniNSF1: andc r4,r9,r10 ; Clean up the old power bits | |
1c79356b | 1212 | mtspr hid0,r4 ; Set up the HID |
55e303ae A |
1213 | mfspr r4,hid0 ; Yes, this is silly, keep it here |
1214 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1215 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1216 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1217 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1218 | mfspr r4,hid0 ; Yes, this is a duplicate, keep it here | |
1c79356b A |
1219 | |
1220 | bt pfNoMSRirb,ciNoMSR ; No MSR... | |
1221 | ||
1222 | mtmsr r5 ; Translation and all off | |
1223 | isync ; Toss prefetch | |
1224 | b ciNoMSRx | |
1225 | ||
1226 | ciNoMSR: | |
1227 | li r0,loadMSR ; Get the MSR setter SC | |
1228 | mr r3,r5 ; Get new MSR | |
1229 | sc ; Set it | |
1230 | ciNoMSRx: | |
1231 | ||
1232 | bf pfAltivecb,cinoDSS ; No Altivec here... | |
1233 | ||
1234 | dssall ; Stop streams | |
1235 | sync | |
1236 | ||
55e303ae | 1237 | cinoDSS: li r5,tlbieLock ; Get the TLBIE lock |
1c79356b | 1238 | li r0,128 ; Get number of TLB entries |
1c79356b A |
1239 | |
1240 | li r6,0 ; Start at 0 | |
55e303ae A |
1241 | bf-- pf64Bitb,citlbhang ; Skip if 32-bit... |
1242 | li r0,1024 ; Get the number of TLB entries | |
1c79356b A |
1243 | |
1244 | citlbhang: lwarx r2,0,r5 ; Get the TLBIE lock | |
1245 | mr. r2,r2 ; Is it locked? | |
1246 | bne- citlbhang ; It is locked, go wait... | |
1247 | stwcx. r0,0,r5 ; Try to get it | |
1248 | bne- citlbhang ; We was beat... | |
1249 | ||
1250 | mtctr r0 ; Set the CTR | |
1251 | ||
1252 | cipurgeTLB: tlbie r6 ; Purge this entry | |
1253 | addi r6,r6,4096 ; Next page | |
1254 | bdnz cipurgeTLB ; Do them all... | |
1255 | ||
1256 | mtcrf 0x80,r11 ; Set SMP capability | |
1257 | sync ; Make sure all TLB purges are done | |
1258 | eieio ; Order, order in the court | |
1259 | ||
1260 | bf pfSMPcapb,cinoSMP ; SMP incapable... | |
1261 | ||
1262 | tlbsync ; Sync all TLBs | |
1263 | sync | |
150bd074 | 1264 | isync |
1c79356b | 1265 | |
55e303ae A |
1266 | bf-- pf64Bitb,cinoSMP ; Skip if 32-bit... |
1267 | ptesync ; Wait for quiet again | |
1268 | sync | |
1269 | ||
1270 | cinoSMP: stw r2,tlbieLock(0) ; Unlock TLBIE lock | |
1271 | ||
1272 | bt++ pf64Bitb,cin64 ; Skip if 64-bit... | |
1c79356b | 1273 | |
1c79356b A |
1274 | rlwinm. r0,r9,0,ice,dce ; Were either of the level 1s on? |
1275 | beq- cinoL1 ; No, no need to flush... | |
1276 | ||
55e303ae A |
1277 | rlwinm. r0,r11,0,pfL1fab,pfL1fab ; do we have L1 flush assist? |
1278 | beq ciswdl1 ; If no hw flush assist, go do by software... | |
1c79356b A |
1279 | |
1280 | mfspr r8,msscr0 ; Get the memory system control register | |
1281 | oris r8,r8,hi16(dl1hwfm) ; Turn on the hardware flush request | |
1282 | ||
1283 | mtspr msscr0,r8 ; Start the flush operation | |
1284 | ||
1285 | ciwdl1f: mfspr r8,msscr0 ; Get the control register again | |
1286 | ||
1287 | rlwinm. r8,r8,0,dl1hwf,dl1hwf ; Has the flush request been reset yet? | |
1288 | bne ciwdl1f ; No, flush is still in progress... | |
1289 | b ciinvdl1 ; Go invalidate l1... | |
1290 | ||
1291 | ; | |
1292 | ; We need to either make this very complicated or to use ROM for | |
1293 | ; the flush. The problem is that if during the following sequence a | |
1294 | ; snoop occurs that invalidates one of the lines in the cache, the | |
1295 | ; PLRU sequence will be altered making it possible to miss lines | |
1296 | ; during the flush. So, we either need to dedicate an area of RAM | |
1297 | ; to each processor, lock use of a RAM area, or use ROM. ROM is | |
1298 | ; by far the easiest. Note that this is not an issue for machines | |
1299 | ; that have harware flush assists. | |
1300 | ; | |
1301 | ||
1302 | ciswdl1: lwz r0,pfl1dSize(r12) ; Get the level 1 cache size | |
0b4e3aa0 A |
1303 | |
1304 | bf 31,cisnlck ; Skip if pfLClck not set... | |
1305 | ||
91447636 A |
1306 | mfspr r4,msscr0 ; ? |
1307 | rlwinm r6,r4,0,0,l2pfes-1 ; ? | |
0b4e3aa0 A |
1308 | mtspr msscr0,r6 ; Set it |
1309 | sync | |
1310 | isync | |
1311 | ||
1312 | mfspr r8,ldstcr ; Save the LDSTCR | |
1313 | li r2,1 ; Get a mask of 0x01 | |
1314 | lis r3,0xFFF0 ; Point to ROM | |
1315 | rlwinm r11,r0,29,3,31 ; Get the amount of memory to handle all indexes | |
1316 | ||
1317 | li r6,0 ; Start here | |
1318 | ||
1319 | cisiniflsh: dcbf r6,r3 ; Flush each line of the range we use | |
1320 | addi r6,r6,32 ; Bump to the next | |
1321 | cmplw r6,r0 ; Have we reached the end? | |
1322 | blt+ cisiniflsh ; Nope, continue initial flush... | |
1323 | ||
1324 | sync ; Make sure it is done | |
1325 | ||
1326 | addi r11,r11,-1 ; Get mask for index wrap | |
1327 | li r6,0 ; Get starting offset | |
1328 | ||
1329 | cislckit: not r5,r2 ; Lock all but 1 way | |
1330 | rlwimi r5,r8,0,0,23 ; Build LDSTCR | |
1331 | mtspr ldstcr,r5 ; Lock a way | |
1332 | sync ; Clear out memory accesses | |
1333 | isync ; Wait for all | |
1334 | ||
1335 | ||
1336 | cistouch: lwzx r10,r3,r6 ; Pick up some trash | |
1337 | addi r6,r6,32 ; Go to the next index | |
1338 | and. r0,r6,r11 ; See if we are about to do next index | |
1339 | bne+ cistouch ; Nope, do more... | |
1340 | ||
1341 | sync ; Make sure it is all done | |
1342 | isync | |
1343 | ||
1344 | sub r6,r6,r11 ; Back up to start + 1 | |
1345 | addi r6,r6,-1 ; Get it right | |
1346 | ||
1347 | cisflush: dcbf r3,r6 ; Flush everything out | |
1348 | addi r6,r6,32 ; Go to the next index | |
1349 | and. r0,r6,r11 ; See if we are about to do next index | |
1350 | bne+ cisflush ; Nope, do more... | |
1351 | ||
1352 | sync ; Make sure it is all done | |
1353 | isync | |
1354 | ||
1355 | ||
1356 | rlwinm. r2,r2,1,24,31 ; Shift to next way | |
1357 | bne+ cislckit ; Do this for all ways... | |
1358 | ||
1359 | mtspr ldstcr,r8 ; Slam back to original | |
1360 | sync | |
1361 | isync | |
1362 | ||
91447636 | 1363 | mtspr msscr0,r4 ; ? |
0b4e3aa0 A |
1364 | sync |
1365 | isync | |
1366 | ||
1367 | b cinoL1 ; Go on to level 2... | |
1368 | ||
1369 | ||
1370 | cisnlck: rlwinm r2,r0,0,1,30 ; Double cache size | |
1c79356b A |
1371 | add r0,r0,r2 ; Get 3 times cache size |
1372 | rlwinm r0,r0,26,6,31 ; Get 3/2 number of cache lines | |
1373 | lis r3,0xFFF0 ; Dead recon ROM address for now | |
1374 | mtctr r0 ; Number of lines to flush | |
1375 | ||
1376 | ciswfldl1a: lwz r2,0(r3) ; Flush anything else | |
1377 | addi r3,r3,32 ; Next line | |
1378 | bdnz ciswfldl1a ; Flush the lot... | |
1379 | ||
1380 | ciinvdl1: sync ; Make sure all flushes have been committed | |
1381 | ||
1382 | mfspr r8,hid0 ; Get the HID0 bits | |
1383 | rlwinm r8,r8,0,dce+1,ice-1 ; Clear cache enables | |
1384 | mtspr hid0,r8 ; and turn off L1 cache | |
1385 | sync ; Make sure all is done | |
0b4e3aa0 A |
1386 | isync |
1387 | ||
1c79356b A |
1388 | ori r8,r8,lo16(icem|dcem|icfim|dcfim) ; Set the HID0 bits for enable, and invalidate |
1389 | sync | |
1390 | isync | |
1391 | ||
1392 | mtspr hid0,r8 ; Start the invalidate and turn on cache | |
1393 | rlwinm r8,r8,0,dcfi+1,icfi-1 ; Turn off the invalidate bits | |
1394 | mtspr hid0,r8 ; Turn off the invalidate (needed for some older machines) | |
1395 | sync | |
0b4e3aa0 | 1396 | |
1c79356b A |
1397 | |
1398 | cinoL1: | |
1399 | ; | |
1400 | ; Flush and disable the level 2 | |
1401 | ; | |
55e303ae A |
1402 | mfsprg r10,2 ; need to check 2 features we did not put in CR |
1403 | rlwinm. r0,r10,0,pfL2b,pfL2b ; do we have L2? | |
1404 | beq cinol2 ; No level 2 cache to flush | |
1c79356b A |
1405 | |
1406 | mfspr r8,l2cr ; Get the L2CR | |
1407 | lwz r3,pfl2cr(r12) ; Get the L2CR value | |
d52fe63f A |
1408 | rlwinm. r0,r8,0,l2e,l2e ; Was the L2 enabled? |
1409 | bne ciflushl2 ; Yes, force flush | |
1410 | cmplwi r8, 0 ; Was the L2 all the way off? | |
1411 | beq ciinvdl2 ; Yes, force invalidate | |
1c79356b A |
1412 | lis r0,hi16(l2sizm|l2clkm|l2ramm|l2ohm) ; Get confiuration bits |
1413 | xor r2,r8,r3 ; Get changing bits? | |
1414 | ori r0,r0,lo16(l2slm|l2dfm|l2bypm) ; More config bits | |
1415 | and. r0,r0,r2 ; Did any change? | |
1416 | bne- ciinvdl2 ; Yes, just invalidate and get PLL synced... | |
1417 | ||
d52fe63f | 1418 | ciflushl2: |
55e303ae A |
1419 | rlwinm. r0,r10,0,pfL2fab,pfL2fab ; hardware-assisted L2 flush? |
1420 | beq ciswfl2 ; Flush not in hardware... | |
1c79356b | 1421 | |
d52fe63f | 1422 | mr r10,r8 ; Take a copy now |
1c79356b | 1423 | |
0b4e3aa0 | 1424 | bf 31,cinol2lck ; Skip if pfLClck not set... |
1c79356b A |
1425 | |
1426 | oris r10,r10,hi16(l2ionlym|l2donlym) ; Set both instruction- and data-only | |
1427 | sync | |
1428 | mtspr l2cr,r10 ; Lock out the cache | |
1429 | sync | |
1430 | isync | |
1431 | ||
1432 | cinol2lck: ori r10,r10,lo16(l2hwfm) ; Request flush | |
1433 | sync ; Make sure everything is done | |
1434 | ||
1435 | mtspr l2cr,r10 ; Request flush | |
1436 | ||
1437 | cihwfl2: mfspr r10,l2cr ; Get back the L2CR | |
1438 | rlwinm. r10,r10,0,l2hwf,l2hwf ; Is the flush over? | |
1439 | bne+ cihwfl2 ; Nope, keep going... | |
1440 | b ciinvdl2 ; Flush done, go invalidate L2... | |
1441 | ||
1442 | ciswfl2: | |
1443 | lwz r0,pfl2Size(r12) ; Get the L2 size | |
d52fe63f | 1444 | oris r2,r8,hi16(l2dom) ; Set L2 to data only mode |
0b4e3aa0 A |
1445 | |
1446 | b ciswfl2doa ; Branch to next line... | |
1447 | ||
1448 | .align 5 | |
1449 | ciswfl2doc: | |
1450 | mtspr l2cr,r2 ; Disable L2 | |
1451 | sync | |
1452 | isync | |
1453 | b ciswfl2dod ; It is off, go invalidate it... | |
1454 | ||
1455 | ciswfl2doa: | |
1456 | b ciswfl2dob ; Branch to next... | |
1457 | ||
1458 | ciswfl2dob: | |
1459 | sync ; Finish memory stuff | |
1460 | isync ; Stop speculation | |
1461 | b ciswfl2doc ; Jump back up and turn on data only... | |
1462 | ciswfl2dod: | |
1c79356b A |
1463 | rlwinm r0,r0,27,5,31 ; Get the number of lines |
1464 | lis r10,0xFFF0 ; Dead recon ROM for now | |
1465 | mtctr r0 ; Set the number of lines | |
1466 | ||
1467 | ciswfldl2a: lwz r0,0(r10) ; Load something to flush something | |
1468 | addi r10,r10,32 ; Next line | |
1469 | bdnz ciswfldl2a ; Do the lot... | |
1470 | ||
55e303ae | 1471 | ciinvdl2: rlwinm r8,r3,0,l2e+1,31 ; Clear the enable bit |
1c79356b A |
1472 | b cinla ; Branch to next line... |
1473 | ||
1474 | .align 5 | |
d52fe63f | 1475 | cinlc: mtspr l2cr,r8 ; Disable L2 |
1c79356b A |
1476 | sync |
1477 | isync | |
1478 | b ciinvl2 ; It is off, go invalidate it... | |
1479 | ||
1480 | cinla: b cinlb ; Branch to next... | |
1481 | ||
1482 | cinlb: sync ; Finish memory stuff | |
1483 | isync ; Stop speculation | |
1484 | b cinlc ; Jump back up and turn off cache... | |
1485 | ||
1486 | ciinvl2: sync | |
1487 | isync | |
d52fe63f A |
1488 | |
1489 | cmplwi r3, 0 ; Should the L2 be all the way off? | |
1490 | beq cinol2 ; Yes, done with L2 | |
1491 | ||
1492 | oris r2,r8,hi16(l2im) ; Get the invalidate flag set | |
1c79356b A |
1493 | |
1494 | mtspr l2cr,r2 ; Start the invalidate | |
1495 | sync | |
1496 | isync | |
1497 | ciinvdl2a: mfspr r2,l2cr ; Get the L2CR | |
55e303ae A |
1498 | mfsprg r0,2 ; need to check a feature in "non-volatile" set |
1499 | rlwinm. r0,r0,0,pfL2ib,pfL2ib ; flush in HW? | |
1500 | beq ciinvdl2b ; Flush not in hardware... | |
1c79356b A |
1501 | rlwinm. r2,r2,0,l2i,l2i ; Is the invalidate still going? |
1502 | bne+ ciinvdl2a ; Assume so, this will take a looong time... | |
1503 | sync | |
1504 | b cinol2 ; No level 2 cache to flush | |
1505 | ciinvdl2b: | |
1506 | rlwinm. r2,r2,0,l2ip,l2ip ; Is the invalidate still going? | |
1507 | bne+ ciinvdl2a ; Assume so, this will take a looong time... | |
1508 | sync | |
d52fe63f | 1509 | mtspr l2cr,r8 ; Turn off the invalidate request |
1c79356b A |
1510 | |
1511 | cinol2: | |
1512 | ||
1513 | ; | |
1514 | ; Flush and enable the level 3 | |
1515 | ; | |
1516 | bf pfL3b,cinol3 ; No level 3 cache to flush | |
1517 | ||
1518 | mfspr r8,l3cr ; Get the L3CR | |
1519 | lwz r3,pfl3cr(r12) ; Get the L3CR value | |
d52fe63f A |
1520 | rlwinm. r0,r8,0,l3e,l3e ; Was the L3 enabled? |
1521 | bne ciflushl3 ; Yes, force flush | |
1522 | cmplwi r8, 0 ; Was the L3 all the way off? | |
1523 | beq ciinvdl3 ; Yes, force invalidate | |
1c79356b A |
1524 | lis r0,hi16(l3pem|l3sizm|l3dxm|l3clkm|l3spom|l3ckspm) ; Get configuration bits |
1525 | xor r2,r8,r3 ; Get changing bits? | |
1526 | ori r0,r0,lo16(l3pspm|l3repm|l3rtm|l3cyam|l3dmemm|l3dmsizm) ; More config bits | |
1527 | and. r0,r0,r2 ; Did any change? | |
1528 | bne- ciinvdl3 ; Yes, just invalidate and get PLL synced... | |
1529 | ||
d52fe63f | 1530 | ciflushl3: |
1c79356b | 1531 | sync ; 7450 book says do this even though not needed |
d52fe63f | 1532 | mr r10,r8 ; Take a copy now |
1c79356b A |
1533 | |
1534 | bf 31,cinol3lck ; Skip if pfL23lck not set... | |
1535 | ||
1536 | oris r10,r10,hi16(l3iom) ; Set instruction-only | |
1537 | ori r10,r10,lo16(l3donlym) ; Set data-only | |
1538 | sync | |
1539 | mtspr l3cr,r10 ; Lock out the cache | |
1540 | sync | |
1541 | isync | |
1542 | ||
1543 | cinol3lck: ori r10,r10,lo16(l3hwfm) ; Request flush | |
1544 | sync ; Make sure everything is done | |
1545 | ||
1546 | mtspr l3cr,r10 ; Request flush | |
1547 | ||
1548 | cihwfl3: mfspr r10,l3cr ; Get back the L3CR | |
1549 | rlwinm. r10,r10,0,l3hwf,l3hwf ; Is the flush over? | |
1550 | bne+ cihwfl3 ; Nope, keep going... | |
1551 | ||
55e303ae | 1552 | ciinvdl3: rlwinm r8,r3,0,l3e+1,31 ; Clear the enable bit |
1c79356b | 1553 | sync ; Make sure of life, liberty, and justice |
d52fe63f | 1554 | mtspr l3cr,r8 ; Disable L3 |
1c79356b A |
1555 | sync |
1556 | ||
d52fe63f A |
1557 | cmplwi r3, 0 ; Should the L3 be all the way off? |
1558 | beq cinol3 ; Yes, done with L3 | |
1c79356b | 1559 | |
d52fe63f | 1560 | ori r8,r8,lo16(l3im) ; Get the invalidate flag set |
1c79356b | 1561 | |
d52fe63f A |
1562 | mtspr l3cr,r8 ; Start the invalidate |
1563 | ||
1564 | ciinvdl3b: mfspr r8,l3cr ; Get the L3CR | |
1565 | rlwinm. r8,r8,0,l3i,l3i ; Is the invalidate still going? | |
1c79356b A |
1566 | bne+ ciinvdl3b ; Assume so... |
1567 | sync | |
1568 | ||
91447636 A |
1569 | lwz r10, pfBootConfig(r12) ; ? |
1570 | rlwinm. r10, r10, 24, 28, 31 ; ? | |
1571 | beq ciinvdl3nopdet ; ? | |
1572 | ||
1573 | mfspr r8,l3pdet ; ? | |
1574 | srw r2, r8, r10 ; ? | |
1575 | rlwimi r2, r8, 0, 24, 31 ; ? | |
1576 | subfic r10, r10, 32 ; ? | |
1577 | li r8, -1 ; ? | |
1578 | ori r2, r2, 0x0080 ; ? | |
1579 | slw r8, r8, r10 ; ? | |
1580 | or r8, r2, r8 ; ? | |
1581 | mtspr l3pdet, r8 ; ? | |
1c79356b A |
1582 | isync |
1583 | ||
7b1edb79 | 1584 | ciinvdl3nopdet: |
d52fe63f A |
1585 | mfspr r8,l3cr ; Get the L3CR |
1586 | rlwinm r8,r8,0,l3clken+1,l3clken-1 ; Clear the clock enable bit | |
1587 | mtspr l3cr,r8 ; Disable the clock | |
1c79356b | 1588 | |
91447636 A |
1589 | li r2,128 ; ? |
1590 | ciinvdl3c: addi r2,r2,-1 ; ? | |
1591 | cmplwi r2,0 ; ? | |
1c79356b A |
1592 | bne+ ciinvdl3c |
1593 | ||
91447636 A |
1594 | mfspr r10,msssr0 ; ? |
1595 | rlwinm r10,r10,0,vgL3TAG+1,vgL3TAG-1 ; ? | |
1596 | mtspr msssr0,r10 ; ? | |
1c79356b A |
1597 | sync |
1598 | ||
d52fe63f | 1599 | mtspr l3cr,r3 ; Enable it as desired |
1c79356b A |
1600 | sync |
1601 | cinol3: | |
55e303ae A |
1602 | mfsprg r0,2 ; need to check a feature in "non-volatile" set |
1603 | rlwinm. r0,r0,0,pfL2b,pfL2b ; is there an L2 cache? | |
1604 | beq cinol2a ; No level 2 cache to enable | |
1c79356b A |
1605 | |
1606 | lwz r3,pfl2cr(r12) ; Get the L2CR value | |
d52fe63f | 1607 | cmplwi r3, 0 ; Should the L2 be all the way off? |
55e303ae | 1608 | beq cinol2a : Yes, done with L2 |
d52fe63f | 1609 | mtspr l2cr,r3 ; Enable it as desired |
1c79356b A |
1610 | sync |
1611 | ||
1612 | ; | |
1613 | ; Invalidate and turn on L1s | |
1614 | ; | |
1615 | ||
0b4e3aa0 A |
1616 | cinol2a: |
1617 | bt 31,cinoexit ; Skip if pfLClck set... | |
1618 | ||
1619 | rlwinm r8,r9,0,dce+1,ice-1 ; Clear the I- and D- cache enables | |
1c79356b A |
1620 | mtspr hid0,r8 ; Turn off dem caches |
1621 | sync | |
1622 | ||
1623 | ori r8,r9,lo16(icem|dcem|icfim|dcfim) ; Set the HID0 bits for enable, and invalidate | |
1624 | rlwinm r9,r8,0,dcfi+1,icfi-1 ; Turn off the invalidate bits | |
1625 | sync | |
1626 | isync | |
1627 | ||
1628 | mtspr hid0,r8 ; Start the invalidate and turn on L1 cache | |
0b4e3aa0 A |
1629 | |
1630 | cinoexit: mtspr hid0,r9 ; Turn off the invalidate (needed for some older machines) and restore entry conditions | |
1c79356b A |
1631 | sync |
1632 | mtmsr r7 ; Restore MSR to entry | |
1633 | isync | |
1634 | blr ; Return... | |
1635 | ||
1636 | ||
55e303ae A |
1637 | ; |
1638 | ; Handle 64-bit architecture | |
1639 | ; This processor can not run without caches, so we just push everything out | |
1640 | ; and flush. It will be relativily clean afterwards | |
1641 | ; | |
1642 | ||
1643 | .align 5 | |
1644 | ||
1645 | cin64: | |
55e303ae A |
1646 | mfspr r10,hid1 ; Save hid1 |
1647 | mfspr r4,hid4 ; Save hid4 | |
1648 | mr r12,r10 ; Really save hid1 | |
1649 | mr r11,r4 ; Get a working copy of hid4 | |
1650 | ||
1651 | li r0,0 ; Get a 0 | |
1652 | eqv r2,r2,r2 ; Get all foxes | |
1653 | ||
1654 | rldimi r10,r0,55,7 ; Clear I$ prefetch bits (7:8) | |
1655 | ||
1656 | isync | |
1657 | mtspr hid1,r10 ; Stick it | |
1658 | mtspr hid1,r10 ; Stick it again | |
1659 | isync | |
1660 | ||
1661 | rldimi r11,r2,38,25 ; Disable D$ prefetch (25:25) | |
1662 | ||
1663 | sync | |
1664 | mtspr hid4,r11 ; Stick it | |
1665 | isync | |
1666 | ||
1667 | li r3,8 ; Set bit 28+32 | |
1668 | sldi r3,r3,32 ; Make it bit 28 | |
1669 | or r3,r3,r11 ; Turn on the flash invalidate L1D$ | |
1670 | ||
1671 | oris r5,r11,0x0600 ; Set disable L1D$ bits | |
1672 | sync | |
1673 | mtspr hid4,r3 ; Invalidate | |
1674 | isync | |
1675 | ||
1676 | mtspr hid4,r5 ; Un-invalidate and disable L1D$ | |
1677 | isync | |
1678 | ||
1679 | lis r8,GUSModeReg ; Get the GUS mode ring address | |
1680 | mfsprg r0,2 ; Get the feature flags | |
1681 | ori r8,r8,0x8000 ; Set to read data | |
1682 | rlwinm. r0,r0,pfSCOMFixUpb+1,31,31 ; Set shift if we need a fix me up | |
1683 | ||
1684 | sync | |
1685 | ||
1686 | mtspr scomc,r8 ; Request the GUS mode | |
1687 | mfspr r11,scomd ; Get the GUS mode | |
1688 | mfspr r8,scomc ; Get back the status (we just ignore it) | |
1689 | sync | |
1690 | isync | |
1691 | ||
1692 | sld r11,r11,r0 ; Fix up if needed | |
1693 | ||
1694 | ori r6,r11,lo16(GUSMdmapen) ; Set the bit that means direct L2 cache address | |
1695 | lis r8,GUSModeReg ; Get GUS mode register address | |
1696 | ||
1697 | sync | |
1698 | ||
1699 | mtspr scomd,r6 ; Set that we want direct L2 mode | |
1700 | mtspr scomc,r8 ; Tell GUS we want direct L2 mode | |
1701 | mfspr r3,scomc ; Get back the status | |
1702 | sync | |
1703 | isync | |
1704 | ||
1705 | li r3,0 ; Clear start point | |
1706 | ||
1707 | cflushlp: lis r6,0x0040 ; Pick 4MB line as our target | |
1708 | or r6,r6,r3 ; Put in the line offset | |
1709 | lwz r5,0(r6) ; Load a line | |
1710 | addis r6,r6,8 ; Roll bit 42:44 | |
1711 | lwz r5,0(r6) ; Load a line | |
1712 | addis r6,r6,8 ; Roll bit 42:44 | |
1713 | lwz r5,0(r6) ; Load a line | |
1714 | addis r6,r6,8 ; Roll bit 42:44 | |
1715 | lwz r5,0(r6) ; Load a line | |
1716 | addis r6,r6,8 ; Roll bit 42:44 | |
1717 | lwz r5,0(r6) ; Load a line | |
1718 | addis r6,r6,8 ; Roll bit 42:44 | |
1719 | lwz r5,0(r6) ; Load a line | |
1720 | addis r6,r6,8 ; Roll bit 42:44 | |
1721 | lwz r5,0(r6) ; Load a line | |
1722 | addis r6,r6,8 ; Roll bit 42:44 | |
1723 | lwz r5,0(r6) ; Load a line | |
1724 | ||
1725 | addi r3,r3,128 ; Next line | |
1726 | andis. r5,r3,8 ; Have we done enough? | |
1727 | beq++ cflushlp ; Not yet... | |
1728 | ||
1729 | sync | |
1730 | ||
1731 | lis r6,0x0040 ; Pick 4MB line as our target | |
1732 | ||
1733 | cflushx: dcbf 0,r6 ; Flush line and invalidate | |
1734 | addi r6,r6,128 ; Next line | |
1735 | andis. r5,r6,0x0080 ; Have we done enough? | |
1736 | beq++ cflushx ; Keep on flushing... | |
1737 | ||
1738 | mr r3,r10 ; Copy current hid1 | |
1739 | rldimi r3,r2,54,9 ; Set force icbi match mode | |
1740 | ||
1741 | li r6,0 ; Set start if ICBI range | |
1742 | isync | |
1743 | mtspr hid1,r3 ; Stick it | |
1744 | mtspr hid1,r3 ; Stick it again | |
1745 | isync | |
1746 | ||
1747 | cflicbi: icbi 0,r6 ; Kill I$ | |
1748 | addi r6,r6,128 ; Next line | |
1749 | andis. r5,r6,1 ; Have we done them all? | |
1750 | beq++ cflicbi ; Not yet... | |
1751 | ||
1752 | lis r8,GUSModeReg ; Get GUS mode register address | |
1753 | ||
1754 | sync | |
1755 | ||
1756 | mtspr scomd,r11 ; Set that we do not want direct mode | |
1757 | mtspr scomc,r8 ; Tell GUS we do not want direct mode | |
1758 | mfspr r3,scomc ; Get back the status | |
1759 | sync | |
1760 | isync | |
4a249263 A |
1761 | |
1762 | isync | |
1763 | mtspr hid0,r9 ; Restore entry hid0 | |
1764 | mfspr r9,hid0 ; Yes, this is silly, keep it here | |
1765 | mfspr r9,hid0 ; Yes, this is a duplicate, keep it here | |
1766 | mfspr r9,hid0 ; Yes, this is a duplicate, keep it here | |
1767 | mfspr r9,hid0 ; Yes, this is a duplicate, keep it here | |
1768 | mfspr r9,hid0 ; Yes, this is a duplicate, keep it here | |
1769 | mfspr r9,hid0 ; Yes, this is a duplicate, keep it here | |
1770 | isync | |
1771 | ||
55e303ae A |
1772 | isync |
1773 | mtspr hid1,r12 ; Restore entry hid1 | |
1774 | mtspr hid1,r12 ; Stick it again | |
1775 | isync | |
1776 | ||
1777 | sync | |
1778 | mtspr hid4,r4 ; Restore entry hid4 | |
1779 | isync | |
1780 | ||
1781 | sync | |
1782 | mtmsr r7 ; Restore MSR to entry | |
1783 | isync | |
1784 | blr ; Return... | |
1785 | ||
1786 | ||
1787 | ||
1c79356b A |
1788 | /* Disables all caches |
1789 | * | |
1790 | * void cacheDisable(void) | |
1791 | * | |
1792 | * Turns off all caches on the processor. They are not flushed. | |
1793 | * | |
1794 | */ | |
1795 | ||
1796 | ; Force a line boundry here | |
1797 | .align 5 | |
1798 | .globl EXT(cacheDisable) | |
1799 | ||
1800 | LEXT(cacheDisable) | |
1801 | ||
1802 | mfsprg r11,2 ; Get CPU specific features | |
1803 | mtcrf 0x83,r11 ; Set feature flags | |
1804 | ||
1805 | bf pfAltivecb,cdNoAlt ; No vectors... | |
1806 | ||
1807 | dssall ; Stop streams | |
1808 | ||
1809 | cdNoAlt: sync | |
1810 | ||
55e303ae A |
1811 | btlr pf64Bitb ; No way to disable a 64-bit machine... |
1812 | ||
1c79356b A |
1813 | mfspr r5,hid0 ; Get the hid |
1814 | rlwinm r5,r5,0,dce+1,ice-1 ; Clear the I- and D- cache enables | |
1815 | mtspr hid0,r5 ; Turn off dem caches | |
1816 | sync | |
1817 | ||
55e303ae A |
1818 | rlwinm. r0,r11,0,pfL2b,pfL2b ; is there an L2? |
1819 | beq cdNoL2 ; Skip if no L2... | |
1820 | ||
1c79356b A |
1821 | mfspr r5,l2cr ; Get the L2 |
1822 | rlwinm r5,r5,0,l2e+1,31 ; Turn off enable bit | |
1823 | ||
1824 | b cinlaa ; Branch to next line... | |
1825 | ||
1826 | .align 5 | |
1827 | cinlcc: mtspr l2cr,r5 ; Disable L2 | |
1828 | sync | |
1829 | isync | |
1830 | b cdNoL2 ; It is off, we are done... | |
1831 | ||
1832 | cinlaa: b cinlbb ; Branch to next... | |
1833 | ||
1834 | cinlbb: sync ; Finish memory stuff | |
1835 | isync ; Stop speculation | |
1836 | b cinlcc ; Jump back up and turn off cache... | |
1837 | ||
1838 | cdNoL2: | |
55e303ae | 1839 | |
1c79356b A |
1840 | bf pfL3b,cdNoL3 ; Skip down if no L3... |
1841 | ||
1842 | mfspr r5,l3cr ; Get the L3 | |
1843 | rlwinm r5,r5,0,l3e+1,31 ; Turn off enable bit | |
1844 | rlwinm r5,r5,0,l3clken+1,l3clken-1 ; Turn off cache enable bit | |
1845 | mtspr l3cr,r5 ; Disable the caches | |
1846 | sync | |
1847 | ||
1848 | cdNoL3: | |
1849 | blr ; Leave... | |
1850 | ||
1851 | ||
1852 | /* Initialize processor thermal monitoring | |
1853 | * void ml_thrm_init(void) | |
1854 | * | |
483a1d10 | 1855 | * Obsolete, deprecated and will be removed. |
1c79356b A |
1856 | */ |
1857 | ||
1858 | ; Force a line boundry here | |
1859 | .align 5 | |
1860 | .globl EXT(ml_thrm_init) | |
1861 | ||
1862 | LEXT(ml_thrm_init) | |
1c79356b A |
1863 | blr |
1864 | ||
1c79356b A |
1865 | /* Set thermal monitor bounds |
1866 | * void ml_thrm_set(unsigned int low, unsigned int high) | |
1867 | * | |
483a1d10 | 1868 | * Obsolete, deprecated and will be removed. |
1c79356b A |
1869 | */ |
1870 | ||
1871 | ; Force a line boundry here | |
1872 | .align 5 | |
1873 | .globl EXT(ml_thrm_set) | |
1874 | ||
1875 | LEXT(ml_thrm_set) | |
483a1d10 | 1876 | blr |
1c79356b A |
1877 | |
1878 | /* Read processor temprature | |
1879 | * unsigned int ml_read_temp(void) | |
1880 | * | |
483a1d10 | 1881 | * Obsolete, deprecated and will be removed. |
1c79356b A |
1882 | */ |
1883 | ||
1884 | ; Force a line boundry here | |
1885 | .align 5 | |
1886 | .globl EXT(ml_read_temp) | |
1887 | ||
1888 | LEXT(ml_read_temp) | |
483a1d10 A |
1889 | li r3,-1 |
1890 | blr | |
1c79356b A |
1891 | |
1892 | /* Throttle processor speed up or down | |
1893 | * unsigned int ml_throttle(unsigned int step) | |
1894 | * | |
1895 | * Returns old speed and sets new. Both step and return are values from 0 to | |
1896 | * 255 that define number of throttle steps, 0 being off and "ictcfim" is max * 2. | |
1897 | * | |
483a1d10 | 1898 | * Obsolete, deprecated and will be removed. |
1c79356b A |
1899 | */ |
1900 | ||
1901 | ; Force a line boundry here | |
1902 | .align 5 | |
1903 | .globl EXT(ml_throttle) | |
1904 | ||
1905 | LEXT(ml_throttle) | |
483a1d10 A |
1906 | li r3,0 |
1907 | blr | |
1c79356b A |
1908 | |
1909 | /* | |
1910 | ** ml_get_timebase() | |
1911 | ** | |
1912 | ** Entry - R3 contains pointer to 64 bit structure. | |
1913 | ** | |
1914 | ** Exit - 64 bit structure filled in. | |
1915 | ** | |
1916 | */ | |
1917 | ; Force a line boundry here | |
1918 | .align 5 | |
1919 | .globl EXT(ml_get_timebase) | |
1920 | ||
1921 | LEXT(ml_get_timebase) | |
1922 | ||
1923 | loop: | |
55e303ae A |
1924 | mftbu r4 |
1925 | mftb r5 | |
1926 | mftbu r6 | |
1927 | cmpw r6, r4 | |
1928 | bne- loop | |
1929 | ||
1930 | stw r4, 0(r3) | |
1931 | stw r5, 4(r3) | |
1932 | ||
1933 | blr | |
1c79356b | 1934 | |
55e303ae A |
1935 | /* |
1936 | * unsigned int cpu_number(void) | |
1937 | * | |
1938 | * Returns the current cpu number. | |
1939 | */ | |
1940 | ||
1941 | .align 5 | |
1942 | .globl EXT(cpu_number) | |
1943 | ||
1944 | LEXT(cpu_number) | |
91447636 A |
1945 | mfsprg r4,1 ; Get the current activation |
1946 | lwz r4,ACT_PER_PROC(r4) ; Get the per_proc block | |
55e303ae A |
1947 | lhz r3,PP_CPU_NUMBER(r4) ; Get CPU number |
1948 | blr ; Return... | |
9bccf70c | 1949 | |
91447636 A |
1950 | /* |
1951 | * processor_t current_processor(void) | |
1952 | * | |
1953 | * Returns the current processor. | |
1954 | */ | |
1955 | ||
1956 | .align 5 | |
1957 | .globl EXT(current_processor) | |
1958 | ||
1959 | LEXT(current_processor) | |
1960 | mfsprg r3,1 ; Get the current activation | |
1961 | lwz r3,ACT_PER_PROC(r3) ; Get the per_proc block | |
1962 | addi r3,r3,PP_PROCESSOR | |
1963 | blr | |
1964 | ||
1965 | #if PROCESSOR_SIZE > PP_PROCESSOR_SIZE | |
1966 | #error processor overflows per_proc | |
1967 | #endif | |
d7e50217 A |
1968 | |
1969 | /* | |
91447636 | 1970 | * ast_t *ast_pending(void) |
55e303ae | 1971 | * |
91447636 A |
1972 | * Returns the address of the pending AST mask for the current processor. |
1973 | */ | |
1974 | ||
1975 | .align 5 | |
1976 | .globl EXT(ast_pending) | |
1977 | ||
1978 | LEXT(ast_pending) | |
1979 | mfsprg r3,1 ; Get the current activation | |
1980 | lwz r3,ACT_PER_PROC(r3) ; Get the per_proc block | |
1981 | addi r3,r3,PP_PENDING_AST | |
1982 | blr ; Return... | |
1983 | ||
1984 | /* | |
1985 | * void machine_set_current_thread(thread_t) | |
1986 | * | |
1987 | * Set the current thread | |
d7e50217 | 1988 | */ |
55e303ae | 1989 | .align 5 |
91447636 | 1990 | .globl EXT(machine_set_current_thread) |
d7e50217 | 1991 | |
91447636 | 1992 | LEXT(machine_set_current_thread) |
55e303ae | 1993 | |
91447636 A |
1994 | mfsprg r4,1 ; Get spr1 |
1995 | lwz r5,ACT_PER_PROC(r4) ; Get the PerProc from the previous active thread | |
1996 | stw r5,ACT_PER_PROC(r3) ; Set the PerProc in the active thread | |
55e303ae A |
1997 | mtsprg 1,r3 ; Set spr1 with the active thread |
1998 | blr ; Return... | |
1999 | ||
2000 | /* | |
55e303ae | 2001 | * thread_t current_thread(void) |
91447636 | 2002 | * thread_t current_act(void) |
55e303ae A |
2003 | * |
2004 | * | |
2005 | * Return the current thread for outside components. | |
2006 | */ | |
2007 | .align 5 | |
55e303ae | 2008 | .globl EXT(current_thread) |
91447636 | 2009 | .globl EXT(current_act) |
55e303ae | 2010 | |
55e303ae | 2011 | LEXT(current_thread) |
91447636 | 2012 | LEXT(current_act) |
55e303ae A |
2013 | |
2014 | mfsprg r3,1 | |
2015 | blr | |
55e303ae A |
2016 | |
2017 | .align 5 | |
2018 | .globl EXT(mach_absolute_time) | |
2019 | LEXT(mach_absolute_time) | |
2020 | 1: mftbu r3 | |
2021 | mftb r4 | |
2022 | mftbu r0 | |
2023 | cmpw r0,r3 | |
91447636 | 2024 | bne-- 1b |
55e303ae | 2025 | blr |
9bccf70c | 2026 | |
1c79356b A |
2027 | /* |
2028 | ** ml_sense_nmi() | |
2029 | ** | |
2030 | */ | |
2031 | ; Force a line boundry here | |
2032 | .align 5 | |
2033 | .globl EXT(ml_sense_nmi) | |
2034 | ||
2035 | LEXT(ml_sense_nmi) | |
2036 | ||
2037 | blr ; Leave... | |
2038 | ||
d52fe63f | 2039 | /* |
91447636 | 2040 | ** ml_set_processor_speed_powertune() |
d52fe63f A |
2041 | ** |
2042 | */ | |
2043 | ; Force a line boundry here | |
2044 | .align 5 | |
5353443c | 2045 | .globl EXT(ml_set_processor_speed_powertune) |
d52fe63f | 2046 | |
5353443c | 2047 | LEXT(ml_set_processor_speed_powertune) |
483a1d10 A |
2048 | mflr r0 ; Save the link register |
2049 | stwu r1, -(FM_ALIGN(4*4)+FM_SIZE)(r1) ; Make some space on the stack | |
2050 | stw r28, FM_ARG0+0x00(r1) ; Save a register | |
2051 | stw r29, FM_ARG0+0x04(r1) ; Save a register | |
2052 | stw r30, FM_ARG0+0x08(r1) ; Save a register | |
2053 | stw r31, FM_ARG0+0x0C(r1) ; Save a register | |
2054 | stw r0, (FM_ALIGN(4*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Save the return | |
9bccf70c | 2055 | |
91447636 A |
2056 | mfsprg r31,1 ; Get the current activation |
2057 | lwz r31,ACT_PER_PROC(r31) ; Get the per_proc block | |
483a1d10 | 2058 | |
483a1d10 A |
2059 | rlwinm r28, r3, 31-dnap, dnap, dnap ; Shift the 1 bit to the dnap+32 bit |
2060 | rlwinm r3, r3, 2, 29, 29 ; Shift the 1 to a 4 and mask | |
2061 | addi r3, r3, pfPowerTune0 ; Add in the pfPowerTune0 offset | |
2062 | lwzx r29, r31, r3 ; Load the PowerTune number 0 or 1 | |
2063 | ||
2064 | sldi r28, r28, 32 ; Shift to the top half | |
2065 | ld r3, pfHID0(r31) ; Load the saved hid0 value | |
2066 | and r28, r28, r3 ; Save the dnap bit | |
2067 | lis r4, hi16(dnapm) ; Make a mask for the dnap bit | |
2068 | sldi r4, r4, 32 ; Shift to the top half | |
2069 | andc r3, r3, r4 ; Clear the dnap bit | |
2070 | or r28, r28, r3 ; Insert the dnap bit as needed for later | |
2071 | ||
2072 | sync | |
2073 | mtspr hid0, r3 ; Turn off dnap in hid0 | |
2074 | mfspr r3, hid0 ; Yes, this is silly, keep it here | |
2075 | mfspr r3, hid0 ; Yes, this is a duplicate, keep it here | |
2076 | mfspr r3, hid0 ; Yes, this is a duplicate, keep it here | |
2077 | mfspr r3, hid0 ; Yes, this is a duplicate, keep it here | |
2078 | mfspr r3, hid0 ; Yes, this is a duplicate, keep it here | |
2079 | mfspr r3, hid0 ; Yes, this is a duplicate, keep it here | |
2080 | isync ; Make sure it is set | |
2081 | ||
2082 | lis r3, hi16(PowerTuneControlReg) ; Write zero to the PCR | |
2083 | ori r3, r3, lo16(PowerTuneControlReg) | |
2084 | li r4, 0 | |
2085 | li r5, 0 | |
2086 | bl _ml_scom_write | |
2087 | ||
2088 | lis r3, hi16(PowerTuneControlReg) ; Write the PowerTune value to the PCR | |
2089 | ori r3, r3, lo16(PowerTuneControlReg) | |
2090 | li r4, 0 | |
2091 | mr r5, r29 | |
2092 | bl _ml_scom_write | |
2093 | ||
2094 | rlwinm r29, r29, 13-6, 6, 7 ; Move to PSR speed location and isolate the requested speed | |
2095 | spsPowerTuneLoop: | |
2096 | lis r3, hi16(PowerTuneStatusReg) ; Read the status from the PSR | |
2097 | ori r3, r3, lo16(PowerTuneStatusReg) | |
2098 | li r4, 0 | |
2099 | bl _ml_scom_read | |
2100 | srdi r5, r5, 32 | |
2101 | rlwinm r0, r5, 0, 6, 7 ; Isolate the current speed | |
2102 | rlwimi r0, r5, 0, 2, 2 ; Copy in the change in progress bit | |
2103 | cmpw r0, r29 ; Compare the requested and current speeds | |
2104 | beq spsPowerTuneDone | |
2105 | rlwinm. r0, r5, 0, 3, 3 | |
2106 | beq spsPowerTuneLoop | |
2107 | ||
2108 | spsPowerTuneDone: | |
2109 | sync | |
2110 | mtspr hid0, r28 ; Turn on dnap in hid0 if needed | |
2111 | mfspr r28, hid0 ; Yes, this is silly, keep it here | |
2112 | mfspr r28, hid0 ; Yes, this is a duplicate, keep it here | |
2113 | mfspr r28, hid0 ; Yes, this is a duplicate, keep it here | |
2114 | mfspr r28, hid0 ; Yes, this is a duplicate, keep it here | |
2115 | mfspr r28, hid0 ; Yes, this is a duplicate, keep it here | |
2116 | mfspr r28, hid0 ; Yes, this is a duplicate, keep it here | |
2117 | isync ; Make sure it is set | |
2118 | ||
483a1d10 A |
2119 | lwz r0, (FM_ALIGN(4*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Get the return |
2120 | lwz r28, FM_ARG0+0x00(r1) ; Restore a register | |
2121 | lwz r29, FM_ARG0+0x04(r1) ; Restore a register | |
2122 | lwz r30, FM_ARG0+0x08(r1) ; Restore a register | |
2123 | lwz r31, FM_ARG0+0x0C(r1) ; Restore a register | |
2124 | lwz r1, FM_BACKPTR(r1) ; Pop the stack | |
2125 | mtlr r0 | |
d52fe63f | 2126 | blr |
d12e1678 | 2127 | |
5353443c A |
2128 | /* |
2129 | ** ml_set_processor_speed_dpll() | |
2130 | ** | |
2131 | */ | |
2132 | ; Force a line boundry here | |
2133 | .align 5 | |
2134 | .globl EXT(ml_set_processor_speed_dpll) | |
2135 | ||
2136 | LEXT(ml_set_processor_speed_dpll) | |
91447636 A |
2137 | mfsprg r5,1 ; Get the current activation |
2138 | lwz r5,ACT_PER_PROC(r5) ; Get the per_proc block | |
5353443c A |
2139 | |
2140 | cmplwi r3, 0 ; Turn off BTIC before low speed | |
2141 | beq spsDPLL1 | |
2142 | mfspr r4, hid0 ; Get the current hid0 value | |
2143 | rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit | |
2144 | sync | |
2145 | mtspr hid0, r4 ; Set the new hid0 value | |
2146 | isync | |
2147 | sync | |
2148 | ||
2149 | spsDPLL1: | |
2150 | mfspr r4, hid1 ; Get the current PLL settings | |
2151 | rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit | |
2152 | stw r4, pfHID1(r5) ; Save the new hid1 value | |
2153 | mtspr hid1, r4 ; Select desired PLL | |
2154 | ||
2155 | cmplwi r3, 0 ; Restore BTIC after high speed | |
2156 | bne spsDPLL2 | |
2157 | lwz r4, pfHID0(r5) ; Load the hid0 value | |
2158 | sync | |
2159 | mtspr hid0, r4 ; Set the hid0 value | |
2160 | isync | |
2161 | sync | |
2162 | spsDPLL2: | |
2163 | blr | |
2164 | ||
2165 | ||
2166 | /* | |
3a60a9f5 A |
2167 | ** ml_set_processor_speed_dfs(divideby) |
2168 | ** divideby == 0 then divide by 1 (full speed) | |
2169 | ** divideby == 1 then divide by 2 (half speed) | |
2170 | ** divideby == 2 then divide by 4 (quarter speed) | |
2171 | ** divideby == 3 then divide by 4 (quarter speed) - preferred | |
5353443c A |
2172 | ** |
2173 | */ | |
2174 | ; Force a line boundry here | |
2175 | .align 5 | |
2176 | .globl EXT(ml_set_processor_speed_dfs) | |
2177 | ||
2178 | LEXT(ml_set_processor_speed_dfs) | |
5353443c | 2179 | |
3a60a9f5 A |
2180 | mfspr r4,hid1 ; Get the current HID1 |
2181 | mfsprg r5,0 ; Get the per_proc_info | |
2182 | rlwimi r4,r3,31-hid1dfs1,hid1dfs0,hid1dfs1 ; Stick the new divider bits in | |
2183 | stw r4,pfHID1(r5) ; Save the new hid1 value | |
5353443c | 2184 | sync |
3a60a9f5 | 2185 | mtspr hid1,r4 ; Set the new HID1 |
5353443c A |
2186 | sync |
2187 | isync | |
2188 | blr | |
2189 | ||
2190 | ||
d12e1678 A |
2191 | /* |
2192 | ** ml_set_processor_voltage() | |
2193 | ** | |
2194 | */ | |
2195 | ; Force a line boundry here | |
2196 | .align 5 | |
2197 | .globl EXT(ml_set_processor_voltage) | |
2198 | ||
2199 | LEXT(ml_set_processor_voltage) | |
91447636 A |
2200 | mfsprg r5,1 ; Get the current activation |
2201 | lwz r5,ACT_PER_PROC(r5) ; Get the per_proc block | |
4a249263 A |
2202 | |
2203 | lwz r6, pfPowerModes(r5) ; Get the supported power modes | |
2204 | ||
2205 | rlwinm. r0, r6, 0, pmDPLLVminb, pmDPLLVminb ; Is DPLL Vmin supported | |
2206 | beq spvDone | |
2207 | ||
2208 | mfspr r4, hid2 ; Get HID2 value | |
2209 | rlwimi r4, r3, 31-hid2vmin, hid2vmin, hid2vmin ; Insert the voltage mode bit | |
2210 | mtspr hid2, r4 ; Set the voltage mode | |
2211 | sync ; Make sure it is done | |
2212 | ||
2213 | spvDone: | |
d12e1678 | 2214 | blr |
483a1d10 A |
2215 | |
2216 | ||
2217 | ; | |
2218 | ; unsigned int ml_scom_write(unsigned int reg, unsigned long long data) | |
2219 | ; 64-bit machines only | |
2220 | ; returns status | |
2221 | ; | |
2222 | ||
2223 | .align 5 | |
2224 | .globl EXT(ml_scom_write) | |
2225 | ||
2226 | LEXT(ml_scom_write) | |
2227 | ||
2228 | rldicr r3,r3,8,47 ; Align register it correctly | |
2229 | rldimi r5,r4,32,0 ; Merge the high part of data | |
2230 | sync ; Clean up everything | |
2231 | ||
2232 | mtspr scomd,r5 ; Stick in the data | |
2233 | mtspr scomc,r3 ; Set write to register | |
2234 | sync | |
2235 | isync | |
2236 | ||
2237 | mfspr r3,scomc ; Read back status | |
2238 | blr ; leave.... | |
2239 | ||
2240 | ; | |
2241 | ; unsigned int ml_read_scom(unsigned int reg, unsigned long long *data) | |
2242 | ; 64-bit machines only | |
2243 | ; returns status | |
2244 | ; ASM Callers: data (r4) can be zero and the 64 bit data will be returned in r5 | |
2245 | ; | |
2246 | ||
2247 | .align 5 | |
2248 | .globl EXT(ml_scom_read) | |
2249 | ||
2250 | LEXT(ml_scom_read) | |
2251 | ||
2252 | mfsprg r0,2 ; Get the feature flags | |
2253 | rldicr r3,r3,8,47 ; Align register it correctly | |
2254 | rlwinm r0,r0,pfSCOMFixUpb+1,31,31 ; Set shift if we need a fix me up | |
2255 | ||
2256 | ori r3,r3,0x8000 ; Set to read data | |
2257 | sync | |
2258 | ||
2259 | mtspr scomc,r3 ; Request the register | |
2260 | mfspr r5,scomd ; Get the register contents | |
2261 | mfspr r3,scomc ; Get back the status | |
2262 | sync | |
2263 | isync | |
2264 | ||
2265 | sld r5,r5,r0 ; Fix up if needed | |
2266 | ||
2267 | cmplwi r4, 0 ; If data pointer is null, just return | |
2268 | beqlr ; the received data in r5 | |
2269 | std r5,0(r4) ; Pass back the received data | |
2270 | blr ; Leave... | |
a3d08fcd A |
2271 | |
2272 | ; | |
2273 | ; Calculates the hdec to dec ratio | |
2274 | ; | |
2275 | ||
2276 | .align 5 | |
2277 | .globl EXT(ml_hdec_ratio) | |
2278 | ||
2279 | LEXT(ml_hdec_ratio) | |
2280 | ||
2281 | li r0,0 ; Clear the EE bit (and everything else for that matter) | |
2282 | mfmsr r11 ; Get the MSR | |
2283 | mtmsrd r0,1 ; Set the EE bit only (do not care about RI) | |
2284 | rlwinm r11,r11,0,MSR_EE_BIT,MSR_EE_BIT ; Isolate just the EE bit | |
2285 | mfmsr r10 ; Refresh our view of the MSR (VMX/FP may have changed) | |
2286 | or r12,r10,r11 ; Turn on EE if on before we turned it off | |
2287 | ||
2288 | mftb r9 ; Get time now | |
2289 | mfspr r2,hdec ; Save hdec | |
2290 | ||
2291 | mhrcalc: mftb r8 ; Get time now | |
2292 | sub r8,r8,r9 ; How many ticks? | |
2293 | cmplwi r8,10000 ; 10000 yet? | |
2294 | blt mhrcalc ; Nope... | |
2295 | ||
2296 | mfspr r9,hdec ; Get hdec now | |
2297 | sub r3,r2,r9 ; How many ticks? | |
2298 | mtmsrd r12,1 ; Flip EE on if needed | |
2299 | blr ; Leave... | |
3a60a9f5 A |
2300 | |
2301 | ||
2302 | ; | |
2303 | ; int setPop(time) | |
2304 | ; | |
2305 | ; Calculates the number of ticks to the supplied event and | |
2306 | ; sets the decrementer. Never set the time for less that the | |
2307 | ; minimum, which is 10, nor more than maxDec, which is usually 0x7FFFFFFF | |
2308 | ; and never more than that but can be set by root. | |
2309 | ; | |
2310 | ; | |
2311 | ||
2312 | .align 7 | |
2313 | .globl EXT(setPop) | |
2314 | ||
2315 | #define kMin 10 | |
2316 | ||
2317 | LEXT(setPop) | |
2318 | ||
2319 | spOver: mftbu r8 ; Get upper time | |
2320 | addic r2,r4,-kMin ; Subtract minimum from target | |
2321 | mftb r9 ; Get lower | |
2322 | addme r11,r3 ; Do you have any bits I could borrow? | |
2323 | mftbu r10 ; Get upper again | |
2324 | subfe r0,r0,r0 ; Get -1 if we went negative 0 otherwise | |
2325 | subc r7,r2,r9 ; Subtract bottom and get carry | |
2326 | cmplw r8,r10 ; Did timebase upper tick? | |
2327 | subfe r6,r8,r11 ; Get the upper difference accounting for borrow | |
2328 | lwz r12,maxDec(0) ; Get the maximum decrementer size | |
2329 | addme r0,r0 ; Get -1 or -2 if anything negative, 0 otherwise | |
2330 | addic r2,r6,-1 ; Set carry if diff < 2**32 | |
2331 | srawi r0,r0,1 ; Make all foxes | |
2332 | subi r10,r12,kMin ; Adjust maximum for minimum adjust | |
2333 | andc r7,r7,r0 ; Pin time at 0 if under minimum | |
2334 | subfe r2,r2,r2 ; 0 if diff > 2**32, -1 otherwise | |
2335 | sub r7,r7,r10 ; Negative if duration is less than (max - min) | |
13fec989 | 2336 | or r2,r2,r0 ; If the duration is negative, it is not too big |
3a60a9f5 A |
2337 | srawi r0,r7,31 ; -1 if duration is too small |
2338 | and r7,r7,r2 ; Clear duration if high part too big | |
2339 | and r7,r7,r0 ; Clear duration if low part too big | |
2340 | bne-- spOver ; Timer ticked... | |
2341 | add r3,r7,r12 ; Add back the max for total | |
2342 | mtdec r3 ; Set the decrementer | |
2343 | blr ; Leave... | |
2344 | ||
2345 |