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