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