]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/machine_routines_asm.s
e81d931cdb4ee1ea29394ef0ca41f90c8bcbf031
[apple/xnu.git] / osfmk / ppc / machine_routines_asm.s
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 #include <ppc/asm.h>
26 #include <ppc/proc_reg.h>
27 #include <cpus.h>
28 #include <assym.s>
29 #include <debug.h>
30 #include <mach/ppc/vm_param.h>
31 #include <ppc/exception.h>
32
33 /* PCI config cycle probing
34 *
35 * boolean_t ml_probe_read(vm_offset_t paddr, unsigned int *val)
36 *
37 * Read the memory location at physical address paddr.
38 * This is a part of a device probe, so there is a good chance we will
39 * have a machine check here. So we have to be able to handle that.
40 * We assume that machine checks are enabled both in MSR and HIDs
41 */
42
43 ; Force a line boundry here
44 .align 5
45 .globl EXT(ml_probe_read)
46
47 LEXT(ml_probe_read)
48
49 mfsprg r9,2 ; Get feature flags
50 mfmsr r0 ; Save the current MSR
51 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
52 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
53 neg r10,r3 ; Number of bytes to end of page
54 rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
55 rlwinm. r10,r10,0,20,31 ; Clear excess junk and test for page bndry
56 mr r12,r3 ; Save the load address
57 mtcrf 0x04,r9 ; Set the features
58 cmplwi cr1,r10,4 ; At least 4 bytes left in page?
59 rlwinm r2,r2,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Clear translation
60 beq- mprdoit ; We are right on the boundary...
61 li r3,0
62 bltlr- cr1 ; No, just return failure...
63
64 mprdoit:
65
66 bt pfNoMSRirb,mprNoMSR ; No MSR...
67
68 mtmsr r2 ; Translation and all off
69 isync ; Toss prefetch
70 b mprNoMSRx
71
72 mprNoMSR:
73 mr r5,r0
74 li r0,loadMSR ; Get the MSR setter SC
75 mr r3,r2 ; Get new MSR
76 sc ; Set it
77 mr r0,r5
78 li r3,0
79 mprNoMSRx:
80
81 mfspr r6, hid0 ; Get a copy of hid0
82
83 rlwinm. r5, r9, 0, pfNoMuMMCKb, pfNoMuMMCKb ; Check for NoMuMMCK
84 bne mprNoMuM
85
86 rlwinm r5, r6, 0, ice+1, ice-1 ; Turn off L1 I-Cache
87 mtspr hid0, r5
88 isync ; Wait for I-Cache off
89 rlwinm r5, r6, 0, mum+1, mum-1 ; Turn off MuM w/ I-Cache on
90 mtspr hid0, r5
91 mprNoMuM:
92
93 ;
94 ; We need to insure that there is no more than 1 BAT register that
95 ; can get a hit. There could be repercussions beyond the ken
96 ; of mortal man. It is best not to tempt fate.
97 ;
98
99 ; Note: we will reload these from the shadow BATs later
100
101 li r10,0 ; Clear a register
102
103 sync ; Make sure all is well
104
105 mtdbatu 1,r10 ; Invalidate DBAT 1
106 mtdbatu 2,r10 ; Invalidate DBAT 2
107 mtdbatu 3,r10 ; Invalidate DBAT 3
108
109 rlwinm r10,r12,0,0,14 ; Round down to a 128k boundary
110 ori r11,r10,0x32 ; Set uncached, coherent, R/W
111 ori r10,r10,2 ; Make the upper half (128k, valid supervisor)
112 mtdbatl 0,r11 ; Set lower BAT first
113 mtdbatu 0,r10 ; Now the upper
114 sync ; Just make sure
115
116 dcbf 0,r12 ; Make sure we kill the cache to avoid paradoxes
117 sync
118
119 ori r11,r2,lo16(MASK(MSR_DR)) ; Turn on data translation
120 mtmsr r11 ; Do it for real
121 isync ; Make sure of it
122
123 eieio ; Make sure of all previous accesses
124 sync ; Make sure it is all caught up
125
126 lwz r11,0(r12) ; Get it and maybe machine check here
127
128 eieio ; Make sure of ordering again
129 sync ; Get caught up yet again
130 isync ; Do not go further till we are here
131
132 mtmsr r2 ; Turn translation back off
133 isync
134
135 mtspr hid0, r6 ; Restore HID0
136 isync
137
138 lis r10,hi16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
139 ori r10,r10,lo16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
140
141 lwz r5,0(r10) ; Pick up DBAT 0 high
142 lwz r6,4(r10) ; Pick up DBAT 0 low
143 lwz r7,8(r10) ; Pick up DBAT 1 high
144 lwz r8,16(r10) ; Pick up DBAT 2 high
145 lwz r9,24(r10) ; Pick up DBAT 3 high
146
147 mtdbatu 0,r5 ; Restore DBAT 0 high
148 mtdbatl 0,r6 ; Restore DBAT 0 low
149 mtdbatu 1,r7 ; Restore DBAT 1 high
150 mtdbatu 2,r8 ; Restore DBAT 2 high
151 mtdbatu 3,r9 ; Restore DBAT 3 high
152 sync
153
154 li r3,1 ; We made it
155
156 mtmsr r0 ; Restore translation and exceptions
157 isync ; Toss speculations
158
159 stw r11,0(r4) ; Save the loaded value
160 blr ; Return...
161
162 ; Force a line boundry here. This means we will be able to check addresses better
163 .align 5
164 .globl EXT(ml_probe_read_mck)
165 LEXT(ml_probe_read_mck)
166
167 /* Read physical address
168 *
169 * unsigned int ml_phys_read_byte(vm_offset_t paddr)
170 *
171 * Read the byte at physical address paddr. Memory should not be cache inhibited.
172 */
173
174 ; Force a line boundry here
175 .align 5
176 .globl EXT(ml_phys_read_byte)
177
178 LEXT(ml_phys_read_byte)
179
180 mfmsr r10 ; Save the current MSR
181 rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
182 rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
183 rlwinm r4,r10,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
184 rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
185
186 mtmsr r4 ; Translation and all off
187 isync ; Toss prefetch
188
189 lbz r3,0(r3) ; Get the byte
190 sync
191
192 mtmsr r10 ; Restore translation and rupts
193 isync
194 blr
195
196 /* Read physical address
197 *
198 * unsigned int ml_phys_read(vm_offset_t paddr)
199 *
200 * Read the word at physical address paddr. Memory should not be cache inhibited.
201 */
202
203 ; Force a line boundry here
204 .align 5
205 .globl EXT(ml_phys_read)
206
207 LEXT(ml_phys_read)
208
209 mfmsr r0 ; Save the current MSR
210 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
211 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
212 rlwinm r4,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
213 rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
214
215 mtmsr r4 ; Translation and all off
216 isync ; Toss prefetch
217
218 lwz r3,0(r3) ; Get the word
219 sync
220
221 mtmsr r0 ; Restore translation and rupts
222 isync
223 blr
224
225 /* Write physical address byte
226 *
227 * void ml_phys_write_byte(vm_offset_t paddr, unsigned int data)
228 *
229 * Write the byte at physical address paddr. Memory should not be cache inhibited.
230 */
231
232 ; Force a line boundry here
233 .align 5
234 .globl EXT(ml_phys_write_byte)
235
236 LEXT(ml_phys_write_byte)
237
238 mfmsr r0 ; Save the current MSR
239 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
240 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
241 rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
242 rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
243
244 mtmsr r5 ; Translation and all off
245 isync ; Toss prefetch
246
247 stb r4,0(r3) ; Set the byte
248 sync
249
250 mtmsr r0 ; Restore translation and rupts
251 isync
252 blr
253
254 /* Write physical address
255 *
256 * void ml_phys_write(vm_offset_t paddr, unsigned int data)
257 *
258 * Write the word at physical address paddr. Memory should not be cache inhibited.
259 */
260
261 ; Force a line boundry here
262 .align 5
263 .globl EXT(ml_phys_write)
264
265 LEXT(ml_phys_write)
266
267 mfmsr r0 ; Save the current MSR
268 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
269 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
270 rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
271 rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
272
273 mtmsr r5 ; Translation and all off
274 isync ; Toss prefetch
275
276 stw r4,0(r3) ; Set the word
277 sync
278
279 mtmsr r0 ; Restore translation and rupts
280 isync
281 blr
282
283
284 /* set interrupts enabled or disabled
285 *
286 * boolean_t set_interrupts_enabled(boolean_t enable)
287 *
288 * Set EE bit to "enable" and return old value as boolean
289 */
290
291 ; Force a line boundry here
292 .align 5
293 .globl EXT(ml_set_interrupts_enabled)
294
295 LEXT(ml_set_interrupts_enabled)
296
297 mfsprg r7,0
298 lwz r4,PP_INTS_ENABLED(r7)
299 mr. r4,r4
300 beq- EXT(fake_set_interrupts_enabled)
301 mfmsr r5 ; Get the current MSR
302 rlwinm r5,r5,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
303 mr r4,r3 ; Save the old value
304 rlwinm r5,r5,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
305 rlwinm r3,r5,17,31,31 ; Set return value
306 rlwimi r5,r4,15,16,16 ; Insert new EE bit
307 andi. r8,r5,lo16(MASK(MSR_EE)) ; Interruptions
308 bne CheckPreemption
309 NoPreemption:
310 mtmsr r5 ; Slam enablement
311 blr
312
313 CheckPreemption:
314 lwz r8,PP_NEED_AST(r7)
315 li r6,AST_URGENT
316 lwz r8,0(r8)
317 lwz r7,PP_PREEMPT_CNT(r7)
318 lis r0,HIGH_ADDR(DoPreemptCall)
319 and. r8,r8,r6
320 ori r0,r0,LOW_ADDR(DoPreemptCall)
321 beq+ NoPreemption
322 cmpi cr0, r7, 0
323 mtmsr r5 ; Restore the MSR now, before we can preempt
324 bnelr+ ; Return if no premption
325 sc ; Preempt
326 blr
327
328
329 /* Emulate a decremeter exception
330 *
331 * void machine_clock_assist(void)
332 *
333 */
334
335 ; Force a line boundry here
336 .align 5
337 .globl EXT(machine_clock_assist)
338
339 LEXT(machine_clock_assist)
340
341 mfsprg r7,0
342 lwz r4,PP_INTS_ENABLED(r7)
343 mr. r4,r4
344 beq- EXT(CreateFakeDEC)
345 blr
346
347 /* Set machine into idle power-saving mode.
348 *
349 * void machine_idle_ppc(void)
350 *
351 * We will use the PPC NAP or DOZE for this.
352 * This call always returns. Must be called with spllo (i.e., interruptions
353 * enabled).
354 *
355 */
356
357
358 ; Force a line boundry here
359 .align 5
360 .globl EXT(machine_idle_ppc)
361
362 LEXT(machine_idle_ppc)
363
364 mfmsr r3 ; Get the current MSR
365 rlwinm r3,r3,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
366 rlwinm r3,r3,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
367 rlwinm r5,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
368 mtmsr r5 ; Hold up interruptions for now
369 isync ; May have messed with fp/vec
370 mfsprg r12,0 ; Get the per_proc_info
371 mfspr r6,hid0 ; Get the current power-saving mode
372 mfsprg r11,2 ; Get CPU specific features
373 rlwinm r6,r6,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though)
374 mtcrf 0xC7,r11 ; Get the facility flags
375
376 lis r4,hi16(napm) ; Assume we can nap
377 bt pfWillNapb,yesnap ; Yeah, nap is ok...
378
379 lis r4,hi16(dozem) ; Assume we can doze
380 bt pfCanDozeb,yesnap ; We can sleep or doze one this machine...
381
382 ori r3,r3,lo16(MASK(MSR_EE)) ; Flip on EE
383 mtmsr r3 ; Turn interruptions back on
384 blr ; Leave...
385
386 yesnap: mftbu r9 ; Get the upper timebase
387 mftb r7 ; Get the lower timebase
388 mftbu r8 ; Get the upper one again
389 cmplw r9,r8 ; Did the top tick?
390 bne- yesnap ; Yeah, need to get it again...
391 stw r8,napStamp(r12) ; Set high order time stamp
392 stw r7,napStamp+4(r12) ; Set low order nap stamp
393
394 rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap?
395 beq miL2PFok
396
397 mfspr r7,msscr0 ; Get currect MSSCR0 value
398 rlwinm r7,r7,0,0,l2pfes-1 ; Dissable L2 Prefetch
399 mtspr msscr0,r7 ; Updates MSSCR0 value
400 sync
401 isync
402
403 miL2PFok:
404 rlwinm. r7,r11,0,pfSlowNapb,pfSlowNapb ; Should nap at slow speed?
405 beq minoslownap
406
407 mfspr r7,hid1 ; Get current HID1 value
408 oris r7,r7,hi16(hid1psm) ; Select PLL1
409 mtspr hid1,r7 ; Update HID1 value
410
411 minoslownap:
412
413 ;
414 ; We have to open up interruptions here because book 4 says that we should
415 ; turn on only the POW bit and that we should have interrupts enabled
416 ; The interrupt handler will detect that nap or doze is set if an interrupt
417 ; is taken and set everything up to return directly to machine_idle_ret.
418 ; So, make sure everything we need there is already set up...
419 ;
420 ori r7,r5,lo16(MASK(MSR_EE)) ; Flip on EE
421 or r6,r6,r4 ; Set nap or doze
422 oris r5,r7,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR
423 mtspr hid0,r6 ; Set up the HID for nap/doze
424 isync ; Make sure it is set
425 mtmsr r7 ; Enable for interrupts
426 rlwinm. r11,r11,0,pfAltivecb,pfAltivecb ; Do we have altivec?
427 beq- minovec ; No...
428 dssall ; Stop the streams before we nap/doze
429
430 minovec: sync ; Make sure queues are clear
431 mtmsr r5 ; Nap or doze
432 isync ; Make sure this takes before we proceed
433 b minovec ; loop if POW does not take
434 ;
435 ; Note that the interrupt handler will turn off the nap/doze bits in the hid.
436 ; Also remember that the interrupt handler will force return to here whenever
437 ; the nap/doze bits are set.
438 ;
439 .globl EXT(machine_idle_ret)
440 LEXT(machine_idle_ret)
441 mtmsr r7 ; Make sure the MSR is what we want
442 isync ; In case we turn on translation
443
444 blr ; Return...
445
446 /* Put machine to sleep.
447 * This call never returns. We always exit sleep via a soft reset.
448 * All external interruptions must be drained at this point and disabled.
449 *
450 * void ml_ppc_sleep(void)
451 *
452 * We will use the PPC SLEEP for this.
453 *
454 * There is one bit of hackery in here: we need to enable for
455 * interruptions when we go to sleep and there may be a pending
456 * decrimenter rupt. So we make the decrimenter 0x7FFFFFFF and enable for
457 * interruptions. The decrimenter rupt vector recognizes this and returns
458 * directly back here.
459 *
460 */
461
462 ; Force a line boundry here
463 .align 5
464 .globl EXT(ml_ppc_sleep)
465
466 LEXT(ml_ppc_sleep)
467
468 #if 0
469 mfmsr r5 ; Hack to spin instead of sleep
470 rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation
471 rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
472 mtmsr r5 ; No talking
473 isync
474
475 deadsleep: addi r3,r3,1 ; Make analyzer happy
476 addi r3,r3,1
477 addi r3,r3,1
478 b deadsleep ; Die the death of 1000 joys...
479 #endif
480
481 mfspr r4,hid0 ; Get the current power-saving mode
482 eqv r10,r10,r10 ; Get all foxes
483 mfsprg r11,2 ; Get CPU specific features
484
485 rlwinm. r5,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before sleep?
486 beq mpsL2PFok
487
488 mfspr r5,msscr0 ; Get currect MSSCR0 value
489 rlwinm r5,r5,0,0,l2pfes-1 ; Dissable L2 Prefetch
490 mtspr msscr0,r5 ; Updates MSSCR0 value
491 sync
492 isync
493
494 mpsL2PFok:
495 mfmsr r5 ; Get the current MSR
496 rlwinm r10,r10,0,1,31 ; Make 0x7FFFFFFF
497 rlwinm r4,r4,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though)
498 mtdec r10 ; Load decrimenter with 0x7FFFFFFF
499 isync ; and make sure,
500 mfdec r9 ; really sure, it gets there
501
502 mtcrf 0x07,r11 ; Get the cache flags, etc
503
504 oris r4,r4,hi16(sleepm) ; Set sleep
505 rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation
506 ;
507 ; Note that we need translation off before we set the HID to sleep. Otherwise
508 ; we will ignore any PTE misses that occur and cause an infinite loop.
509 ;
510 bt pfNoMSRirb,mpsNoMSR ; No MSR...
511
512 mtmsr r5 ; Translation off
513 isync ; Toss prefetch
514 b mpsNoMSRx
515
516 mpsNoMSR:
517 li r0,loadMSR ; Get the MSR setter SC
518 mr r3,r5 ; Get new MSR
519 sc ; Set it
520 mpsNoMSRx:
521
522 ori r3,r5,lo16(MASK(MSR_EE)) ; Flip on EE
523 sync
524 mtspr hid0,r4 ; Set up the HID to sleep
525
526 mtmsr r3 ; Enable for interrupts to drain decrimenter
527
528 add r6,r4,r5 ; Just waste time
529 add r6,r6,r4 ; A bit more
530 add r6,r6,r5 ; A bit more
531
532 mtmsr r5 ; Interruptions back off
533 isync ; Toss prefetch
534
535 ;
536 ; We are here with translation off, interrupts off, all possible
537 ; interruptions drained off, and a decrimenter that will not pop.
538 ;
539
540 bl EXT(cacheInit) ; Clear out the caches. This will leave them on
541 bl EXT(cacheDisable) ; Turn off all caches
542
543 mfmsr r5 ; Get the current MSR
544 oris r5,r5,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR
545 ; Leave EE off because power goes off shortly
546
547 slSleepNow: sync ; Sync it all up
548 mtmsr r5 ; Do sleep with interruptions enabled
549 isync ; Take a pill
550 b slSleepNow ; Go back to sleep if we wake up...
551
552
553
554 /* Initialize all caches including the TLBs
555 *
556 * void cacheInit(void)
557 *
558 * This is used to force the caches to an initial clean state. First, we
559 * check if the cache is on, if so, we need to flush the contents to memory.
560 * Then we invalidate the L1. Next, we configure and invalidate the L2 etc.
561 * Finally we turn on all of the caches
562 *
563 * Note that if translation is not disabled when this is called, the TLB will not
564 * be completely clear after return.
565 *
566 */
567
568 ; Force a line boundry here
569 .align 5
570 .globl EXT(cacheInit)
571
572 LEXT(cacheInit)
573
574 mfsprg r12,0 ; Get the per_proc_info
575 mfspr r9,hid0 ; Get the current power-saving mode
576
577 mfsprg r11,2 ; Get CPU specific features
578 mfmsr r7 ; Get the current MSR
579 rlwinm r4,r9,0,dpm+1,doze-1 ; Clear all possible power-saving modes (also disable DPM)
580 rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
581 rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
582 rlwimi r11,r11,pfLClckb+1,31,31 ; Move pfLClck to another position (to keep from using non-volatile CRs)
583 rlwinm r5,r7,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation
584 rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
585 mtcrf 0x87,r11 ; Get the feature flags
586 mtspr hid0,r4 ; Set up the HID
587
588 bt pfNoMSRirb,ciNoMSR ; No MSR...
589
590 mtmsr r5 ; Translation and all off
591 isync ; Toss prefetch
592 b ciNoMSRx
593
594 ciNoMSR:
595 li r0,loadMSR ; Get the MSR setter SC
596 mr r3,r5 ; Get new MSR
597 sc ; Set it
598 ciNoMSRx:
599
600 bf pfAltivecb,cinoDSS ; No Altivec here...
601
602 dssall ; Stop streams
603 sync
604
605 cinoDSS: lis r5,hi16(EXT(tlb_system_lock)) ; Get the TLBIE lock
606 li r0,128 ; Get number of TLB entries
607 ori r5,r5,lo16(EXT(tlb_system_lock)) ; Grab up the bottom part
608
609 li r6,0 ; Start at 0
610
611 citlbhang: lwarx r2,0,r5 ; Get the TLBIE lock
612 mr. r2,r2 ; Is it locked?
613 bne- citlbhang ; It is locked, go wait...
614 stwcx. r0,0,r5 ; Try to get it
615 bne- citlbhang ; We was beat...
616
617 mtctr r0 ; Set the CTR
618
619 cipurgeTLB: tlbie r6 ; Purge this entry
620 addi r6,r6,4096 ; Next page
621 bdnz cipurgeTLB ; Do them all...
622
623 mtcrf 0x80,r11 ; Set SMP capability
624 sync ; Make sure all TLB purges are done
625 eieio ; Order, order in the court
626
627 bf pfSMPcapb,cinoSMP ; SMP incapable...
628
629 tlbsync ; Sync all TLBs
630 sync
631 isync
632
633 cinoSMP: stw r2,0(r5) ; Unlock TLBIE lock
634
635 cror cr0_eq,pfL1ib,pfL1db ; Check for either I- or D-cache
636 bf- cr0_eq,cinoL1 ; No level 1 to flush...
637 rlwinm. r0,r9,0,ice,dce ; Were either of the level 1s on?
638 beq- cinoL1 ; No, no need to flush...
639
640 bf pfL1fab,ciswdl1 ; If no hw flush assist, go do by software...
641
642 mfspr r8,msscr0 ; Get the memory system control register
643 oris r8,r8,hi16(dl1hwfm) ; Turn on the hardware flush request
644
645 mtspr msscr0,r8 ; Start the flush operation
646
647 ciwdl1f: mfspr r8,msscr0 ; Get the control register again
648
649 rlwinm. r8,r8,0,dl1hwf,dl1hwf ; Has the flush request been reset yet?
650 bne ciwdl1f ; No, flush is still in progress...
651 b ciinvdl1 ; Go invalidate l1...
652
653 ;
654 ; We need to either make this very complicated or to use ROM for
655 ; the flush. The problem is that if during the following sequence a
656 ; snoop occurs that invalidates one of the lines in the cache, the
657 ; PLRU sequence will be altered making it possible to miss lines
658 ; during the flush. So, we either need to dedicate an area of RAM
659 ; to each processor, lock use of a RAM area, or use ROM. ROM is
660 ; by far the easiest. Note that this is not an issue for machines
661 ; that have harware flush assists.
662 ;
663
664 ciswdl1: lwz r0,pfl1dSize(r12) ; Get the level 1 cache size
665
666 bf 31,cisnlck ; Skip if pfLClck not set...
667
668 mfspr r4,msscr0 ; ?
669 rlwinm r6,r4,0,0,l2pfes-1 ; ?
670 mtspr msscr0,r6 ; Set it
671 sync
672 isync
673
674 mfspr r8,ldstcr ; Save the LDSTCR
675 li r2,1 ; Get a mask of 0x01
676 lis r3,0xFFF0 ; Point to ROM
677 rlwinm r11,r0,29,3,31 ; Get the amount of memory to handle all indexes
678
679 li r6,0 ; Start here
680
681 cisiniflsh: dcbf r6,r3 ; Flush each line of the range we use
682 addi r6,r6,32 ; Bump to the next
683 cmplw r6,r0 ; Have we reached the end?
684 blt+ cisiniflsh ; Nope, continue initial flush...
685
686 sync ; Make sure it is done
687
688 addi r11,r11,-1 ; Get mask for index wrap
689 li r6,0 ; Get starting offset
690
691 cislckit: not r5,r2 ; Lock all but 1 way
692 rlwimi r5,r8,0,0,23 ; Build LDSTCR
693 mtspr ldstcr,r5 ; Lock a way
694 sync ; Clear out memory accesses
695 isync ; Wait for all
696
697
698 cistouch: lwzx r10,r3,r6 ; Pick up some trash
699 addi r6,r6,32 ; Go to the next index
700 and. r0,r6,r11 ; See if we are about to do next index
701 bne+ cistouch ; Nope, do more...
702
703 sync ; Make sure it is all done
704 isync
705
706 sub r6,r6,r11 ; Back up to start + 1
707 addi r6,r6,-1 ; Get it right
708
709 cisflush: dcbf r3,r6 ; Flush everything out
710 addi r6,r6,32 ; Go to the next index
711 and. r0,r6,r11 ; See if we are about to do next index
712 bne+ cisflush ; Nope, do more...
713
714 sync ; Make sure it is all done
715 isync
716
717
718 rlwinm. r2,r2,1,24,31 ; Shift to next way
719 bne+ cislckit ; Do this for all ways...
720
721 mtspr ldstcr,r8 ; Slam back to original
722 sync
723 isync
724
725 mtspr msscr0,r4 ; ?
726 sync
727 isync
728
729 b cinoL1 ; Go on to level 2...
730
731
732 cisnlck: rlwinm r2,r0,0,1,30 ; Double cache size
733 add r0,r0,r2 ; Get 3 times cache size
734 rlwinm r0,r0,26,6,31 ; Get 3/2 number of cache lines
735 lis r3,0xFFF0 ; Dead recon ROM address for now
736 mtctr r0 ; Number of lines to flush
737
738 ciswfldl1a: lwz r2,0(r3) ; Flush anything else
739 addi r3,r3,32 ; Next line
740 bdnz ciswfldl1a ; Flush the lot...
741
742 ciinvdl1: sync ; Make sure all flushes have been committed
743
744 mfspr r8,hid0 ; Get the HID0 bits
745 rlwinm r8,r8,0,dce+1,ice-1 ; Clear cache enables
746 mtspr hid0,r8 ; and turn off L1 cache
747 sync ; Make sure all is done
748 isync
749
750 ori r8,r8,lo16(icem|dcem|icfim|dcfim) ; Set the HID0 bits for enable, and invalidate
751 sync
752 isync
753
754 mtspr hid0,r8 ; Start the invalidate and turn on cache
755 rlwinm r8,r8,0,dcfi+1,icfi-1 ; Turn off the invalidate bits
756 mtspr hid0,r8 ; Turn off the invalidate (needed for some older machines)
757 sync
758
759
760 cinoL1:
761 ;
762 ; Flush and disable the level 2
763 ;
764 bf pfL2b,cinol2 ; No level 2 cache to flush
765
766 mfspr r8,l2cr ; Get the L2CR
767 lwz r3,pfl2cr(r12) ; Get the L2CR value
768 rlwinm. r0,r8,0,l2e,l2e ; Was the L2 enabled?
769 bne ciflushl2 ; Yes, force flush
770 cmplwi r8, 0 ; Was the L2 all the way off?
771 beq ciinvdl2 ; Yes, force invalidate
772 lis r0,hi16(l2sizm|l2clkm|l2ramm|l2ohm) ; Get confiuration bits
773 xor r2,r8,r3 ; Get changing bits?
774 ori r0,r0,lo16(l2slm|l2dfm|l2bypm) ; More config bits
775 and. r0,r0,r2 ; Did any change?
776 bne- ciinvdl2 ; Yes, just invalidate and get PLL synced...
777
778 ciflushl2:
779 bf pfL2fab,ciswfl2 ; Flush not in hardware...
780
781 mr r10,r8 ; Take a copy now
782
783 bf 31,cinol2lck ; Skip if pfLClck not set...
784
785 oris r10,r10,hi16(l2ionlym|l2donlym) ; Set both instruction- and data-only
786 sync
787 mtspr l2cr,r10 ; Lock out the cache
788 sync
789 isync
790
791 cinol2lck: ori r10,r10,lo16(l2hwfm) ; Request flush
792 sync ; Make sure everything is done
793
794 mtspr l2cr,r10 ; Request flush
795
796 cihwfl2: mfspr r10,l2cr ; Get back the L2CR
797 rlwinm. r10,r10,0,l2hwf,l2hwf ; Is the flush over?
798 bne+ cihwfl2 ; Nope, keep going...
799 b ciinvdl2 ; Flush done, go invalidate L2...
800
801 ciswfl2:
802 lwz r0,pfl2Size(r12) ; Get the L2 size
803 oris r2,r8,hi16(l2dom) ; Set L2 to data only mode
804
805 b ciswfl2doa ; Branch to next line...
806
807 .align 5
808 ciswfl2doc:
809 mtspr l2cr,r2 ; Disable L2
810 sync
811 isync
812 b ciswfl2dod ; It is off, go invalidate it...
813
814 ciswfl2doa:
815 b ciswfl2dob ; Branch to next...
816
817 ciswfl2dob:
818 sync ; Finish memory stuff
819 isync ; Stop speculation
820 b ciswfl2doc ; Jump back up and turn on data only...
821 ciswfl2dod:
822 rlwinm r0,r0,27,5,31 ; Get the number of lines
823 lis r10,0xFFF0 ; Dead recon ROM for now
824 mtctr r0 ; Set the number of lines
825
826 ciswfldl2a: lwz r0,0(r10) ; Load something to flush something
827 addi r10,r10,32 ; Next line
828 bdnz ciswfldl2a ; Do the lot...
829
830 ciinvdl2: rlwinm r8,r3,0,l2e+1,31 ; Use the saved L2CR and clear the enable bit
831 b cinla ; Branch to next line...
832
833 .align 5
834 cinlc: mtspr l2cr,r8 ; Disable L2
835 sync
836 isync
837 b ciinvl2 ; It is off, go invalidate it...
838
839 cinla: b cinlb ; Branch to next...
840
841 cinlb: sync ; Finish memory stuff
842 isync ; Stop speculation
843 b cinlc ; Jump back up and turn off cache...
844
845 ciinvl2: sync
846 isync
847
848 cmplwi r3, 0 ; Should the L2 be all the way off?
849 beq cinol2 ; Yes, done with L2
850
851 oris r2,r8,hi16(l2im) ; Get the invalidate flag set
852
853 mtspr l2cr,r2 ; Start the invalidate
854 sync
855 isync
856 ciinvdl2a: mfspr r2,l2cr ; Get the L2CR
857 bf pfL2ib,ciinvdl2b ; Flush not in hardware...
858 rlwinm. r2,r2,0,l2i,l2i ; Is the invalidate still going?
859 bne+ ciinvdl2a ; Assume so, this will take a looong time...
860 sync
861 b cinol2 ; No level 2 cache to flush
862 ciinvdl2b:
863 rlwinm. r2,r2,0,l2ip,l2ip ; Is the invalidate still going?
864 bne+ ciinvdl2a ; Assume so, this will take a looong time...
865 sync
866 mtspr l2cr,r8 ; Turn off the invalidate request
867
868 cinol2:
869
870 ;
871 ; Flush and enable the level 3
872 ;
873 bf pfL3b,cinol3 ; No level 3 cache to flush
874
875 mfspr r8,l3cr ; Get the L3CR
876 lwz r3,pfl3cr(r12) ; Get the L3CR value
877 rlwinm. r0,r8,0,l3e,l3e ; Was the L3 enabled?
878 bne ciflushl3 ; Yes, force flush
879 cmplwi r8, 0 ; Was the L3 all the way off?
880 beq ciinvdl3 ; Yes, force invalidate
881 lis r0,hi16(l3pem|l3sizm|l3dxm|l3clkm|l3spom|l3ckspm) ; Get configuration bits
882 xor r2,r8,r3 ; Get changing bits?
883 ori r0,r0,lo16(l3pspm|l3repm|l3rtm|l3cyam|l3dmemm|l3dmsizm) ; More config bits
884 and. r0,r0,r2 ; Did any change?
885 bne- ciinvdl3 ; Yes, just invalidate and get PLL synced...
886
887 ciflushl3:
888 sync ; 7450 book says do this even though not needed
889 mr r10,r8 ; Take a copy now
890
891 bf 31,cinol3lck ; Skip if pfL23lck not set...
892
893 oris r10,r10,hi16(l3iom) ; Set instruction-only
894 ori r10,r10,lo16(l3donlym) ; Set data-only
895 sync
896 mtspr l3cr,r10 ; Lock out the cache
897 sync
898 isync
899
900 cinol3lck: ori r10,r10,lo16(l3hwfm) ; Request flush
901 sync ; Make sure everything is done
902
903 mtspr l3cr,r10 ; Request flush
904
905 cihwfl3: mfspr r10,l3cr ; Get back the L3CR
906 rlwinm. r10,r10,0,l3hwf,l3hwf ; Is the flush over?
907 bne+ cihwfl3 ; Nope, keep going...
908
909 ciinvdl3: rlwinm r8,r3,0,l3e+1,31 ; Use saved L3CR value and clear the enable bit
910 sync ; Make sure of life, liberty, and justice
911 mtspr l3cr,r8 ; Disable L3
912 sync
913
914 cmplwi r3, 0 ; Should the L3 be all the way off?
915 beq cinol3 ; Yes, done with L3
916
917 ori r8,r8,lo16(l3im) ; Get the invalidate flag set
918
919 mtspr l3cr,r8 ; Start the invalidate
920
921 ciinvdl3b: mfspr r8,l3cr ; Get the L3CR
922 rlwinm. r8,r8,0,l3i,l3i ; Is the invalidate still going?
923 bne+ ciinvdl3b ; Assume so...
924 sync
925
926 lwz r10, pfBootConfig(r12) ; ?
927 rlwinm. r10, r10, 24, 28, 31 ; ?
928 beq ciinvdl3nopdet ; ?
929
930 mfspr r8,l3pdet ; ?
931 srw r2, r8, r10 ; ?
932 rlwimi r2, r8, 0, 24, 31 ; ?
933 subfic r10, r10, 32 ; ?
934 li r8, -1 ; ?
935 ori r2, r2, 0x0080 ; ?
936 slw r8, r8, r10 ; ?
937 or r8, r2, r8 ; ?
938 mtspr l3pdet, r8 ; ?
939 isync
940
941 ciinvdl3nopdet:
942 mfspr r8,l3cr ; Get the L3CR
943 rlwinm r8,r8,0,l3clken+1,l3clken-1 ; Clear the clock enable bit
944 mtspr l3cr,r8 ; Disable the clock
945
946 li r2,128 ; ?
947 ciinvdl3c: addi r2,r2,-1 ; ?
948 cmplwi r2,0 ; ?
949 bne+ ciinvdl3c
950
951 mfspr r10,msssr0 ; ?
952 rlwinm r10,r10,0,vgL3TAG+1,vgL3TAG-1 ; ?
953 mtspr msssr0,r10 ; ?
954 sync
955
956 mtspr l3cr,r3 ; Enable it as desired
957 sync
958 cinol3:
959 bf pfL2b,cinol2a ; No level 2 cache to enable
960
961 lwz r3,pfl2cr(r12) ; Get the L2CR value
962 cmplwi r3, 0 ; Should the L2 be all the way off?
963 beq cinol2a : Yes, done with L2
964 mtspr l2cr,r3 ; Enable it as desired
965 sync
966
967 ;
968 ; Invalidate and turn on L1s
969 ;
970
971 cinol2a:
972 bt 31,cinoexit ; Skip if pfLClck set...
973
974 rlwinm r8,r9,0,dce+1,ice-1 ; Clear the I- and D- cache enables
975 mtspr hid0,r8 ; Turn off dem caches
976 sync
977
978 ori r8,r9,lo16(icem|dcem|icfim|dcfim) ; Set the HID0 bits for enable, and invalidate
979 rlwinm r9,r8,0,dcfi+1,icfi-1 ; Turn off the invalidate bits
980 sync
981 isync
982
983 mtspr hid0,r8 ; Start the invalidate and turn on L1 cache
984
985 cinoexit: mtspr hid0,r9 ; Turn off the invalidate (needed for some older machines) and restore entry conditions
986 sync
987 mtmsr r7 ; Restore MSR to entry
988 isync
989 blr ; Return...
990
991
992 /* Disables all caches
993 *
994 * void cacheDisable(void)
995 *
996 * Turns off all caches on the processor. They are not flushed.
997 *
998 */
999
1000 ; Force a line boundry here
1001 .align 5
1002 .globl EXT(cacheDisable)
1003
1004 LEXT(cacheDisable)
1005
1006 mfsprg r11,2 ; Get CPU specific features
1007 mtcrf 0x83,r11 ; Set feature flags
1008
1009 bf pfAltivecb,cdNoAlt ; No vectors...
1010
1011 dssall ; Stop streams
1012
1013 cdNoAlt: sync
1014
1015 mfspr r5,hid0 ; Get the hid
1016 rlwinm r5,r5,0,dce+1,ice-1 ; Clear the I- and D- cache enables
1017 mtspr hid0,r5 ; Turn off dem caches
1018 sync
1019
1020 bf pfL2b,cdNoL2 ; Skip if no L2...
1021
1022 mfspr r5,l2cr ; Get the L2
1023 rlwinm r5,r5,0,l2e+1,31 ; Turn off enable bit
1024
1025 b cinlaa ; Branch to next line...
1026
1027 .align 5
1028 cinlcc: mtspr l2cr,r5 ; Disable L2
1029 sync
1030 isync
1031 b cdNoL2 ; It is off, we are done...
1032
1033 cinlaa: b cinlbb ; Branch to next...
1034
1035 cinlbb: sync ; Finish memory stuff
1036 isync ; Stop speculation
1037 b cinlcc ; Jump back up and turn off cache...
1038
1039 cdNoL2:
1040
1041 bf pfL3b,cdNoL3 ; Skip down if no L3...
1042
1043 mfspr r5,l3cr ; Get the L3
1044 rlwinm r5,r5,0,l3e+1,31 ; Turn off enable bit
1045 rlwinm r5,r5,0,l3clken+1,l3clken-1 ; Turn off cache enable bit
1046 mtspr l3cr,r5 ; Disable the caches
1047 sync
1048
1049 cdNoL3:
1050 blr ; Leave...
1051
1052
1053 /* Initialize processor thermal monitoring
1054 * void ml_thrm_init(void)
1055 *
1056 * Build initial TAU registers and start them all going.
1057 * We ca not do this at initial start up because we need to have the processor frequency first.
1058 * And just why is this in assembler when it does not have to be?? Cause I am just too
1059 * lazy to open up a "C" file, thats why.
1060 */
1061
1062 ; Force a line boundry here
1063 .align 5
1064 .globl EXT(ml_thrm_init)
1065
1066 LEXT(ml_thrm_init)
1067
1068 mfsprg r12,0 ; Get the per_proc blok
1069 lis r11,hi16(EXT(gPEClockFrequencyInfo)) ; Get top of processor information
1070 mfsprg r10,2 ; Get CPU specific features
1071 ori r11,r11,lo16(EXT(gPEClockFrequencyInfo)) ; Get bottom of processor information
1072 mtcrf 0x40,r10 ; Get the installed features
1073
1074 li r3,lo16(thrmtidm|thrmvm) ; Set for lower-than thermal event at 0 degrees
1075 bflr pfThermalb ; No thermal monitoring on this cpu
1076 mtspr thrm1,r3 ; Do it
1077
1078 lwz r3,thrmthrottleTemp(r12) ; Get our throttle temprature
1079 rlwinm r3,r3,31-thrmthre,thrmthrs,thrmthre ; Position it
1080 ori r3,r3,lo16(thrmvm) ; Set for higher-than event
1081 mtspr thrm2,r3 ; Set it
1082
1083 lis r4,hi16(1000000) ; Top of million
1084 ;
1085 ; Note: some CPU manuals say this is processor clocks, some say bus rate. The latter
1086 ; makes more sense because otherwise we can not get over about 400MHz.
1087 #if 0
1088 lwz r3,PECFIcpurate(r11) ; Get the processor speed
1089 #else
1090 lwz r3,PECFIbusrate(r11) ; Get the bus speed
1091 #endif
1092 ori r4,r4,lo16(1000000) ; Bottom of million
1093 lis r7,hi16(thrmsitvm>>1) ; Get top of highest possible value
1094 divwu r3,r3,r4 ; Get number of cycles per microseconds
1095 ori r7,r7,lo16(thrmsitvm>>1) ; Get the bottom of the highest possible value
1096 addi r3,r3,1 ; Insure we have enough
1097 mulli r3,r3,20 ; Get 20 microseconds worth of cycles
1098 cmplw r3,r7 ; Check against max
1099 ble+ smallenuf ; It is ok...
1100 mr r3,r7 ; Saturate
1101
1102 smallenuf: rlwinm r3,r3,31-thrmsitve,thrmsitvs,thrmsitve ; Position
1103 ori r3,r3,lo16(thrmem) ; Enable with at least 20micro sec sample
1104 stw r3,thrm3val(r12) ; Save this in case we need it later
1105 mtspr thrm3,r3 ; Do it
1106 blr
1107
1108
1109 /* Set thermal monitor bounds
1110 * void ml_thrm_set(unsigned int low, unsigned int high)
1111 *
1112 * Set TAU to interrupt below low and above high. A value of
1113 * zero disables interruptions in that direction.
1114 */
1115
1116 ; Force a line boundry here
1117 .align 5
1118 .globl EXT(ml_thrm_set)
1119
1120 LEXT(ml_thrm_set)
1121
1122 mfmsr r0 ; Get the MSR
1123 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
1124 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
1125 rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear EE bit
1126 mtmsr r6
1127 isync
1128
1129 mfsprg r12,0 ; Get the per_proc blok
1130
1131 rlwinm. r6,r3,31-thrmthre,thrmthrs,thrmthre ; Position it and see if enabled
1132 mfsprg r9,2 ; Get CPU specific features
1133 stw r3,thrmlowTemp(r12) ; Set the low temprature
1134 mtcrf 0x40,r9 ; See if we can thermal this machine
1135 rlwinm r9,r9,(((31-thrmtie)+(pfThermIntb+1))&31),thrmtie,thrmtie ; Set interrupt enable if this machine can handle it
1136 bf pfThermalb,tsetcant ; No can do...
1137 beq tsetlowo ; We are setting the low off...
1138 ori r6,r6,lo16(thrmtidm|thrmvm) ; Set the lower-than and valid bit
1139 or r6,r6,r9 ; Set interruption request if supported
1140
1141 tsetlowo: mtspr thrm1,r6 ; Cram the register
1142
1143 rlwinm. r6,r4,31-thrmthre,thrmthrs,thrmthre ; Position it and see if enabled
1144 stw r4,thrmhighTemp(r12) ; Set the high temprature
1145 beq tsethigho ; We are setting the high off...
1146 ori r6,r6,lo16(thrmvm) ; Set valid bit
1147 or r6,r6,r9 ; Set interruption request if supported
1148
1149 tsethigho: mtspr thrm2,r6 ; Cram the register
1150
1151 tsetcant: mtmsr r0 ; Reenable interruptions
1152 blr ; Leave...
1153
1154 /* Read processor temprature
1155 * unsigned int ml_read_temp(void)
1156 *
1157 */
1158
1159 ; Force a line boundry here
1160 .align 5
1161 .globl EXT(ml_read_temp)
1162
1163 LEXT(ml_read_temp)
1164
1165 mfmsr r9 ; Save the MSR
1166 li r5,15 ; Starting point for ranging (start at 15 so we do not overflow)
1167 rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
1168 rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
1169 rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
1170 mfsprg r7,2 ; Get CPU specific features
1171 mtmsr r8 ; Do not allow interruptions
1172 mtcrf 0x40,r7 ; See if we can thermal this machine
1173 bf pfThermalb,thrmcant ; No can do...
1174
1175 mfspr r11,thrm1 ; Save thrm1
1176
1177 thrmrange: rlwinm r4,r5,31-thrmthre,thrmthrs,thrmthre ; Position it
1178 ori r4,r4,lo16(thrmtidm|thrmvm) ; Flip on the valid bit and make comparision for less than
1179
1180 mtspr thrm1,r4 ; Set the test value
1181
1182 thrmreada: mfspr r3,thrm1 ; Get the thermal register back
1183 rlwinm. r0,r3,0,thrmtiv,thrmtiv ; Has it settled yet?
1184 beq+ thrmreada ; Nope...
1185
1186 rlwinm. r0,r3,0,thrmtin,thrmtin ; Are we still under the threshold?
1187 bne thrmsearch ; No, we went over...
1188
1189 addi r5,r5,16 ; Start by trying every 16 degrees
1190 cmplwi r5,127 ; Have we hit the max?
1191 blt- thrmrange ; Got some more to do...
1192
1193 thrmsearch: rlwinm r4,r5,31-thrmthre,thrmthrs,thrmthre ; Position it
1194 ori r4,r4,lo16(thrmtidm|thrmvm) ; Flip on the valid bit and make comparision for less than
1195
1196 mtspr thrm1,r4 ; Set the test value
1197
1198 thrmread: mfspr r3,thrm1 ; Get the thermal register back
1199 rlwinm. r0,r3,0,thrmtiv,thrmtiv ; Has it settled yet?
1200 beq+ thrmread ; Nope...
1201
1202 rlwinm. r0,r3,0,thrmtin,thrmtin ; Are we still under the threshold?
1203 beq thrmdone ; No, we hit it...
1204 addic. r5,r5,-1 ; Go down a degree
1205 bge+ thrmsearch ; Try again (until we are below freezing)...
1206
1207 thrmdone: addi r3,r5,1 ; Return the temprature (bump it up to make it correct)
1208 mtspr thrm1,r11 ; Restore the thermal register
1209 mtmsr r9 ; Re-enable interruptions
1210 blr ; Leave...
1211
1212 thrmcant: eqv r3,r3,r3 ; Return bogus temprature because we can not read it
1213 mtmsr r9 ; Re-enable interruptions
1214 blr ; Leave...
1215
1216 /* Throttle processor speed up or down
1217 * unsigned int ml_throttle(unsigned int step)
1218 *
1219 * Returns old speed and sets new. Both step and return are values from 0 to
1220 * 255 that define number of throttle steps, 0 being off and "ictcfim" is max * 2.
1221 *
1222 */
1223
1224 ; Force a line boundry here
1225 .align 5
1226 .globl EXT(ml_throttle)
1227
1228 LEXT(ml_throttle)
1229
1230 mfmsr r9 ; Save the MSR
1231 rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
1232 rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
1233 rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
1234 cmplwi r3,lo16(ictcfim>>1) ; See if we are going too far
1235 mtmsr r8 ; Do not allow interruptions
1236 isync
1237 ble+ throtok ; Throttle value is ok...
1238 li r3,lo16(ictcfim>>1) ; Set max
1239
1240 throtok: rlwinm. r4,r3,1,ictcfib,ictcfie ; Set the throttle
1241 beq throtoff ; Skip if we are turning it off...
1242 ori r4,r4,lo16(thrmvm) ; Turn on the valid bit
1243
1244 throtoff: mfspr r3,ictc ; Get the old throttle
1245 mtspr ictc,r4 ; Set the new
1246 rlwinm r3,r3,31,1,31 ; Shift throttle value over
1247 mtmsr r9 ; Restore interruptions
1248 blr ; Return...
1249
1250 /*
1251 ** ml_get_timebase()
1252 **
1253 ** Entry - R3 contains pointer to 64 bit structure.
1254 **
1255 ** Exit - 64 bit structure filled in.
1256 **
1257 */
1258 ; Force a line boundry here
1259 .align 5
1260 .globl EXT(ml_get_timebase)
1261
1262 LEXT(ml_get_timebase)
1263
1264 loop:
1265 mftbu r4
1266 mftb r5
1267 mftbu r6
1268 cmpw r6, r4
1269 bne- loop
1270
1271 stw r4, 0(r3)
1272 stw r5, 4(r3)
1273
1274 blr
1275
1276 /*
1277 * The routine that implements cpu_number.
1278 */
1279
1280 .align 5
1281 .globl EXT(cpu_number)
1282
1283 LEXT(cpu_number)
1284
1285 mfmsr r9 /* Save the old MSR */
1286 rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
1287 rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
1288 rlwinm r8,r9,0,17,15 /* Clear interruptions */
1289 mtmsr r8 /* Interrupts off */
1290 isync
1291 mfsprg r7,0 /* Get per-proc block */
1292 lhz r3,PP_CPU_NUMBER(r7) /* Get CPU number */
1293 mtmsr r9 /* Restore interruptions to entry */
1294 blr /* Return... */
1295
1296 /*
1297 ** ml_sense_nmi()
1298 **
1299 */
1300 ; Force a line boundry here
1301 .align 5
1302 .globl EXT(ml_sense_nmi)
1303
1304 LEXT(ml_sense_nmi)
1305
1306 blr ; Leave...
1307
1308 /*
1309 ** ml_set_processor_speed()
1310 **
1311 */
1312 ; Force a line boundry here
1313 .align 5
1314 .globl EXT(ml_set_processor_speed)
1315
1316 LEXT(ml_set_processor_speed)
1317 mfsprg r5, 0 ; Get the per_proc_info
1318
1319 cmpli cr0, r3, 0 ; Turn off BTIC before low speed
1320 beq sps1
1321 mfspr r4, hid0 ; Get the current hid0 value
1322 rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit
1323 sync
1324 mtspr hid0, r4 ; Set the new hid0 value
1325 isync
1326 sync
1327
1328 sps1:
1329 mfspr r4, hid1 ; Get the current PLL settings
1330 rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit
1331 stw r4, pfHID1(r5) ; Save the new hid1 value
1332 mtspr hid1, r4 ; Select desired PLL
1333
1334 cmpli cr0, r3, 0 ; Restore BTIC after high speed
1335 bne sps2
1336 lwz r4, pfHID0(r5) ; Load the hid0 value
1337 sync
1338 mtspr hid0, r4 ; Set the hid0 value
1339 isync
1340 sync
1341
1342 sps2:
1343 blr
1344
1345 /*
1346 ** ml_set_processor_voltage()
1347 **
1348 */
1349 ; Force a line boundry here
1350 .align 5
1351 .globl EXT(ml_set_processor_voltage)
1352
1353 LEXT(ml_set_processor_voltage)
1354 mfspr r4, hid2 ; Get HID2 value
1355 rlwimi r4, r3, 31-hid2vmin, hid2vmin, hid2vmin ; Insert the voltage mode bit
1356 mtspr hid2, r4 ; Set the voltage mode
1357 sync ; Make sure it is done
1358 blr