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