/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <ppc/asm.h>
#include <ppc/proc_reg.h>
-#include <cpus.h>
#include <assym.s>
#include <debug.h>
#include <mach/ppc/vm_param.h>
.align 5
CheckPreemption:
- mfsprg r7,0
- ori r5,r5,lo16(MASK(MSR_EE)) ; Turn on the enable
- lwz r8,PP_NEED_AST(r7) ; Get pointer to AST flags
mfsprg r9,1 ; Get current activation
+ lwz r7,ACT_PER_PROC(r9) ; Get the per_proc block
+ ori r5,r5,lo16(MASK(MSR_EE)) ; Turn on the enable
+ lwz r8,PP_PENDING_AST(r7) ; Get pending AST mask
li r6,AST_URGENT ; Get the type we will preempt for
lwz r7,ACT_PREEMPT_CNT(r9) ; Get preemption count
- lwz r8,0(r8) ; Get AST flags
lis r0,hi16(DoPreemptCall) ; High part of Preempt FW call
cmpwi cr1,r7,0 ; Are preemptions masked off?
and. r8,r8,r6 ; Are we urgent?
sc ; Preempt
blr
-/* Emulate a decremeter exception
- *
- * void machine_clock_assist(void)
- *
- */
+; Force a line boundry here
+ .align 5
+ .globl EXT(timer_update)
+
+LEXT(timer_update)
+ stw r4,TIMER_HIGHCHK(r3)
+ eieio
+ stw r5,TIMER_LOW(r3)
+ eieio
+ stw r4,TIMER_HIGH(r3)
+ blr
; Force a line boundry here
.align 5
- .globl EXT(machine_clock_assist)
+ .globl EXT(timer_grab)
-LEXT(machine_clock_assist)
+LEXT(timer_grab)
+0: lwz r11,TIMER_HIGH(r3)
+ lwz r4,TIMER_LOW(r3)
+ isync
+ lwz r9,TIMER_HIGHCHK(r3)
+ cmpw r11,r9
+ bne-- 0b
+ mr r3,r11
+ blr
- mfsprg r7,0
- lwz r4,PP_INTS_ENABLED(r7)
- mr. r4,r4
- bnelr+ cr0
- b EXT(CreateFakeDEC)
+; Force a line boundry here
+ .align 5
+ .globl EXT(timer_event)
+
+LEXT(timer_event)
+ mfsprg r10,1 ; Get the current activation
+ lwz r10,ACT_PER_PROC(r10) ; Get the per_proc block
+ addi r10,r10,PP_PROCESSOR
+ lwz r11,CURRENT_TIMER(r10)
+
+ lwz r9,TIMER_LOW(r11)
+ lwz r2,TIMER_TSTAMP(r11)
+ add r0,r9,r3
+ subf r5,r2,r0
+ cmplw r5,r9
+ bge++ 0f
+
+ lwz r6,TIMER_HIGH(r11)
+ addi r6,r6,1
+ stw r6,TIMER_HIGHCHK(r11)
+ eieio
+ stw r5,TIMER_LOW(r11)
+ eieio
+ stw r6,TIMER_HIGH(r11)
+ b 1f
+
+0: stw r5,TIMER_LOW(r11)
+
+1: stw r4,CURRENT_TIMER(r10)
+ stw r3,TIMER_TSTAMP(r4)
+ blr
/* Set machine into idle power-saving mode.
*
- * void machine_idle_ppc(void)
+ * void machine_idle(void)
*
* We will use the PPC NAP or DOZE for this.
* This call always returns. Must be called with spllo (i.e., interruptions
; Force a line boundry here
.align 5
- .globl EXT(machine_idle_ppc)
+ .globl EXT(machine_idle)
-LEXT(machine_idle_ppc)
+LEXT(machine_idle)
- lis r0,hi16(MASK(MSR_VEC)) ; Get the vector flag
+ mfsprg r12,1 ; Get the current activation
+ lwz r12,ACT_PER_PROC(r12) ; Get the per_proc block
+ lhz r10,PP_CPU_FLAGS(r12) ; Get the flags
+ lwz r11,PP_INTS_ENABLED(r12) ; Get interrupt enabled state
+ andi. r10,r10,SignalReady ; Are Signal ready?
+ cmpwi cr1,r11,0 ; Are interrupt disabled?
+ cror cr0_eq, cr1_eq, cr0_eq ; Interrupt disabled or Signal not ready?
mfmsr r3 ; Save the MSR
+
+ beq-- nonap ; Yes, return after re-enabling interrupts
+ lis r0,hi16(MASK(MSR_VEC)) ; Get the vector flag
ori r0,r0,lo16(MASK(MSR_FP)) ; Add the FP flag
andc r3,r3,r0 ; Clear VEC and FP
ori r0,r0,lo16(MASK(MSR_EE)) ; Drop EE also
mtmsr r5 ; Hold up interruptions for now
isync ; May have messed with fp/vec
- mfsprg r12,0 ; Get the per_proc_info
mfsprg r11,2 ; Get CPU specific features
mfspr r6,hid0 ; Get the current power-saving mode
mtcrf 0xC7,r11 ; Get the facility flags
lis r4,hi16(dozem) ; Assume we can doze
bt pfCanDozeb,yesnap ; We can sleep or doze one this machine...
+
+nonap: ori r3,r3,lo16(MASK(MSR_EE)) ; Flip on EE
- ori r3,r3,lo16(MASK(MSR_EE)) ; Flip on EE
mtmsr r3 ; Turn interruptions back on
blr ; Leave...
mftb r7 ; Get the lower timebase
mftbu r8 ; Get the upper one again
cmplw r9,r8 ; Did the top tick?
- bne- yesnap ; Yeah, need to get it again...
+ bne-- yesnap ; Yeah, need to get it again...
stw r8,napStamp(r12) ; Set high order time stamp
stw r7,napStamp+4(r12) ; Set low order nap stamp
- rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap?
- beq miL2PFok
+ rlwinm. r0,r11,0,pfAltivecb,pfAltivecb ; Do we have altivec?
+ beq-- minovec ; No...
+ dssall ; Stop the streams before we nap/doze
+ sync
+ lwz r8,napStamp(r12) ; Reload high order time stamp
+clearpipe:
+ cmplw r8,r8
+ bne- clearpipe
+ isync
+
+minovec: rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap?
+ beq++ miL2PFok
mfspr r7,msscr0 ; Get currect MSSCR0 value
rlwinm r7,r7,0,0,l2pfes-1 ; Disable L2 Prefetch
oris r7,r7,hi16(hid1psm) ; Select PLL1
mtspr hid1,r7 ; Update HID1 value
-minoslownap:
;
; We have to open up interruptions here because book 4 says that we should
-; turn on only the POW bit and that we should have interrupts enabled
+; turn on only the POW bit and that we should have interrupts enabled.
; The interrupt handler will detect that nap or doze is set if an interrupt
; is taken and set everything up to return directly to machine_idle_ret.
; So, make sure everything we need there is already set up...
;
+minoslownap:
lis r10,hi16(dozem|napm|sleepm) ; Mask of power management bits
bf-- pf64Bitb,mipNSF1 ; skip if 32-bit...
sldi r4,r4,32 ; Position the flags
sldi r10,r10,32 ; Position the masks
-
-mipNSF1: andc r6,r6,r10 ; Clean up the old power bits
-
- ori r7,r5,lo16(MASK(MSR_EE)) ; Flip on EE
+mipNSF1: li r2,lo16(MASK(MSR_DR)|MASK(MSR_IR)) ; Get the translation mask
+ andc r6,r6,r10 ; Clean up the old power bits
+ ori r7,r5,lo16(MASK(MSR_EE)) ; Flip on EE to make exit msr
+ andc r5,r5,r2 ; Clear IR and DR from current MSR
or r6,r6,r4 ; Set nap or doze
- oris r5,r7,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR
+ ori r5,r5,lo16(MASK(MSR_EE)) ; Flip on EE to make nap msr
+ oris r2,r5,hi16(MASK(MSR_POW)) ; Turn on power management in next MSR
sync
mtspr hid0,r6 ; Set up the HID for nap/doze
mfspr r6,hid0 ; Yes, this is a duplicate, keep it here
mfspr r6,hid0 ; Yes, this is a duplicate, keep it here
isync ; Make sure it is set
-
- mtmsr r7 ; Enable for interrupts
- rlwinm. r11,r11,0,pfAltivecb,pfAltivecb ; Do we have altivec?
- beq- minovec ; No...
- dssall ; Stop the streams before we nap/doze
-minovec: sync ; Make sure queues are clear
- mtmsr r5 ; Nap or doze
+
+;
+; Turn translation off to nap
+;
+
+ bt pfNoMSRirb,miNoMSR ; Jump if we need to use SC for this...
+ mtmsr r5 ; Turn translation off, interrupts on
+ isync ; Wait for it
+ b miNoMSRx ; Jump back in line...
+
+miNoMSR: mr r3,r5 ; Pass in the new MSR value
+ li r0,loadMSR ; MSR setter ultrafast
+ sc ; Do it to it like you never done before...
+
+miNoMSRx: bf-- pf64Bitb,mipowloop ; skip if 32-bit...
+
+ li r3,0x10 ; Fancy nap threshold is 0x10 ticks
+ mftb r8 ; Get the low half of the time base
+ mfdec r4 ; Get the decrementer ticks
+ cmplw r4,r3 ; Less than threshold?
+ blt mipowloop
+
+ mtdec r3 ; Load decrementer with threshold
+ isync ; and make sure,
+ mfdec r3 ; really sure, it gets there
+
+ rlwinm r6,r2,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear out the EE bit
+ sync ; Make sure queues are clear
+ mtmsr r6 ; Set MSR with EE off but POW on
+ isync ; Make sure this takes before we proceed
+
+ mftb r9 ; Get the low half of the time base
+ sub r9,r9,r8 ; Get the number of ticks spent waiting
+ sub r4,r4,r9 ; Adjust the decrementer value
+
+ mtdec r4 ; Load decrementer with the rest of the timeout
+ isync ; and make sure,
+ mfdec r4 ; really sure, it gets there
+
+mipowloop:
+ sync ; Make sure queues are clear
+ mtmsr r2 ; Nap or doze, MSR with POW, EE set, translation off
isync ; Make sure this takes before we proceed
- b minovec ; loop if POW does not take
+ b mipowloop ; loop if POW does not take
+
;
; Note that the interrupt handler will turn off the nap/doze bits in the hid.
; Also remember that the interrupt handler will force return to here whenever
LEXT(machine_idle_ret)
mtmsr r7 ; Make sure the MSR is what we want
isync ; In case we turn on translation
-
+;
+; Protect against a lost decrementer trap if the current decrementer value is negative
+; by more than 10 ticks, re-arm it since it is unlikely to fire at this point...
+; A hardware interrupt got us out of machine_idle and may also be contributing to this state
+;
+ mfdec r6 ; Get decrementer
+ cmpwi cr0,r6,-10 ; Compare decrementer with -10
+ bgelr++ ; Return if greater
+ li r0,1 ; Load 1
+ mtdec r0 ; Set decrementer to 1
blr ; Return...
/* Put machine to sleep.
* This call never returns. We always exit sleep via a soft reset.
* All external interruptions must be drained at this point and disabled.
*
- * void ml_ppc_sleep(void)
+ * void ml_ppc_do_sleep(void)
*
* We will use the PPC SLEEP for this.
*
; Force a line boundry here
.align 5
- .globl EXT(ml_ppc_sleep)
+ .globl EXT(ml_ppc_do_sleep)
-LEXT(ml_ppc_sleep)
+LEXT(ml_ppc_do_sleep)
#if 0
mfmsr r5 ; Hack to spin instead of sleep
b deadsleep ; Die the death of 1000 joys...
#endif
- mfsprg r12,0 ; Get the per_proc_info
- mfspr r4,hid0 ; Get the current power-saving mode
- eqv r10,r10,r10 ; Get all foxes
+ mfsprg r12,1 ; Get the current activation
+ lwz r12,ACT_PER_PROC(r12) ; Get the per_proc block
mfsprg r11,2 ; Get CPU specific features
+ eqv r10,r10,r10 ; Get all foxes
+ mtcrf 0x04,r11 ; move pfNoMSRirb to cr5
+ mfspr r4,hid0 ; Get the current power-saving mode
+ mtcrf 0x02,r11 ; move pf64Bit to cr6
rlwinm. r5,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before sleep?
beq mpsL2PFok
isync
mpsL2PFok:
- rlwinm. r5,r11,0,pf64Bitb,pf64Bitb ; PM bits are shifted on 64bit systems.
- bne mpsPF64bit
+ bt++ pf64Bitb,mpsPF64bit ; PM bits are shifted on 64bit systems.
rlwinm r4,r4,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though)
oris r4,r4,hi16(sleepm) ; Set sleep
- b mpsClearDEC
+ b mpsClearDEC
mpsPF64bit:
- lis r5, hi16(dozem|napm|sleepm) ; Clear all possible power-saving modes (not DPM though)
+ lis r5, hi16(dozem|napm|sleepm) ; Clear all possible power-saving modes (not DPM though)
sldi r5, r5, 32
andc r4, r4, r5
- lis r5, hi16(napm) ; Set sleep
-// lis r5, hi16(dozem) ; Set sleep
+ lis r5, hi16(napm) ; Set sleep
sldi r5, r5, 32
- or r4, r4, r5
+ or r4, r4, r5
mpsClearDEC:
mfmsr r5 ; Get the current MSR
isync ; and make sure,
mfdec r9 ; really sure, it gets there
- mtcrf 0x07,r11 ; Get the cache flags, etc
-
+ li r2,1 ; Prepare for 64 bit
rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation
;
; Note that we need translation off before we set the HID to sleep. Otherwise
; we will ignore any PTE misses that occur and cause an infinite loop.
;
+ bf++ pf64Bitb,mpsCheckMSR ; check 64-bit processor
+ rldimi r5,r2,63,MSR_SF_BIT ; set SF bit (bit 0)
+ mtmsrd r5 ; set 64-bit mode, turn off EE, DR, and IR
+ isync ; Toss prefetch
+ b mpsNoMSRx
+
+mpsCheckMSR:
bt pfNoMSRirb,mpsNoMSR ; No MSR...
mtmsr r5 ; Translation off
ori r11,r11,SleepState ; Marked SleepState
sth r11,PP_CPU_FLAGS(r12) ; Set the flags
dcbf r10,r12
+
+ mfsprg r11,2 ; Get CPU specific features
+ rlwinm. r0,r11,0,pf64Bitb,pf64Bitb ; Test for 64 bit processor
+ eqv r4,r4,r4 ; Get all foxes
+ rlwinm r4,r4,0,1,31 ; Make 0x7FFFFFFF
+ beq slSleepNow ; skip if 32-bit...
+ li r3, 0x4000 ; Cause decrimenter to roll over soon
+ mtdec r3 ; Load decrimenter with 0x00004000
+ isync ; and make sure,
+ mfdec r3 ; really sure, it gets there
+
slSleepNow:
sync ; Sync it all up
mtmsr r5 ; Do sleep with interruptions enabled
isync ; Take a pill
+ mtdec r4 ; Load decrimenter with 0x7FFFFFFF
+ isync ; and make sure,
+ mfdec r3 ; really sure, it gets there
b slSleepNow ; Go back to sleep if we wake up...
.align 5
cin64:
- li r10,hi16(dozem|napm|sleepm) ; Mask of power management bits we want cleared
- sldi r10,r10,32 ; Position the masks
- andc r9,r9,r10 ; Clean up the old power bits
- mr r4,r9
- isync
- mtspr hid0,r4 ; Set up the HID
- mfspr r4,hid0 ; Yes, this is silly, keep it here
- mfspr r4,hid0 ; Yes, this is a duplicate, keep it here
- mfspr r4,hid0 ; Yes, this is a duplicate, keep it here
- mfspr r4,hid0 ; Yes, this is a duplicate, keep it here
- mfspr r4,hid0 ; Yes, this is a duplicate, keep it here
- mfspr r4,hid0 ; Yes, this is a duplicate, keep it here
- isync
-
mfspr r10,hid1 ; Save hid1
mfspr r4,hid4 ; Save hid4
mr r12,r10 ; Really save hid1
mfspr r3,scomc ; Get back the status
sync
isync
-
+
+ isync
+ mtspr hid0,r9 ; Restore entry hid0
+ mfspr r9,hid0 ; Yes, this is silly, keep it here
+ mfspr r9,hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r9,hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r9,hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r9,hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r9,hid0 ; Yes, this is a duplicate, keep it here
+ isync
+
isync
mtspr hid1,r12 ; Restore entry hid1
mtspr hid1,r12 ; Stick it again
/* Initialize processor thermal monitoring
* void ml_thrm_init(void)
*
- * Build initial TAU registers and start them all going.
- * We ca not do this at initial start up because we need to have the processor frequency first.
- * And just why is this in assembler when it does not have to be?? Cause I am just too
- * lazy to open up a "C" file, thats why.
+ * Obsolete, deprecated and will be removed.
*/
; Force a line boundry here
.globl EXT(ml_thrm_init)
LEXT(ml_thrm_init)
-
- mfsprg r12,0 ; Get the per_proc blok
- lis r11,hi16(EXT(gPEClockFrequencyInfo)) ; Get top of processor information
- mfsprg r10,2 ; Get CPU specific features
- ori r11,r11,lo16(EXT(gPEClockFrequencyInfo)) ; Get bottom of processor information
- mtcrf 0x40,r10 ; Get the installed features
-
- li r3,lo16(thrmtidm|thrmvm) ; Set for lower-than thermal event at 0 degrees
- bflr pfThermalb ; No thermal monitoring on this cpu
- mtspr thrm1,r3 ; Do it
-
- lwz r3,thrmthrottleTemp(r12) ; Get our throttle temprature
- rlwinm r3,r3,31-thrmthre,thrmthrs,thrmthre ; Position it
- ori r3,r3,lo16(thrmvm) ; Set for higher-than event
- mtspr thrm2,r3 ; Set it
-
- lis r4,hi16(1000000) ; Top of million
-;
-; Note: some CPU manuals say this is processor clocks, some say bus rate. The latter
-; makes more sense because otherwise we can not get over about 400MHz.
-#if 0
- lwz r3,PECFIcpurate(r11) ; Get the processor speed
-#else
- lwz r3,PECFIbusrate(r11) ; Get the bus speed
-#endif
- ori r4,r4,lo16(1000000) ; Bottom of million
- lis r7,hi16(thrmsitvm>>1) ; Get top of highest possible value
- divwu r3,r3,r4 ; Get number of cycles per microseconds
- ori r7,r7,lo16(thrmsitvm>>1) ; Get the bottom of the highest possible value
- addi r3,r3,1 ; Insure we have enough
- mulli r3,r3,20 ; Get 20 microseconds worth of cycles
- cmplw r3,r7 ; Check against max
- ble+ smallenuf ; It is ok...
- mr r3,r7 ; Saturate
-
-smallenuf: rlwinm r3,r3,31-thrmsitve,thrmsitvs,thrmsitve ; Position
- ori r3,r3,lo16(thrmem) ; Enable with at least 20micro sec sample
- stw r3,thrm3val(r12) ; Save this in case we need it later
- mtspr thrm3,r3 ; Do it
blr
-
/* Set thermal monitor bounds
* void ml_thrm_set(unsigned int low, unsigned int high)
*
- * Set TAU to interrupt below low and above high. A value of
- * zero disables interruptions in that direction.
+ * Obsolete, deprecated and will be removed.
*/
; Force a line boundry here
.globl EXT(ml_thrm_set)
LEXT(ml_thrm_set)
-
- mfmsr r0 ; Get the MSR
- rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
- rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
- rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear EE bit
- mtmsr r6
- isync
-
- mfsprg r12,0 ; Get the per_proc blok
-
- rlwinm. r6,r3,31-thrmthre,thrmthrs,thrmthre ; Position it and see if enabled
- mfsprg r9,2 ; Get CPU specific features
- stw r3,thrmlowTemp(r12) ; Set the low temprature
- mtcrf 0x40,r9 ; See if we can thermal this machine
- rlwinm r9,r9,(((31-thrmtie)+(pfThermIntb+1))&31),thrmtie,thrmtie ; Set interrupt enable if this machine can handle it
- bf pfThermalb,tsetcant ; No can do...
- beq tsetlowo ; We are setting the low off...
- ori r6,r6,lo16(thrmtidm|thrmvm) ; Set the lower-than and valid bit
- or r6,r6,r9 ; Set interruption request if supported
-
-tsetlowo: mtspr thrm1,r6 ; Cram the register
-
- rlwinm. r6,r4,31-thrmthre,thrmthrs,thrmthre ; Position it and see if enabled
- stw r4,thrmhighTemp(r12) ; Set the high temprature
- beq tsethigho ; We are setting the high off...
- ori r6,r6,lo16(thrmvm) ; Set valid bit
- or r6,r6,r9 ; Set interruption request if supported
-
-tsethigho: mtspr thrm2,r6 ; Cram the register
-
-tsetcant: mtmsr r0 ; Reenable interruptions
- blr ; Leave...
+ blr
/* Read processor temprature
* unsigned int ml_read_temp(void)
*
+ * Obsolete, deprecated and will be removed.
*/
; Force a line boundry here
.globl EXT(ml_read_temp)
LEXT(ml_read_temp)
-
- mfmsr r9 ; Save the MSR
- li r5,15 ; Starting point for ranging (start at 15 so we do not overflow)
- rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
- rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
- rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
- mfsprg r7,2 ; Get CPU specific features
- mtmsr r8 ; Do not allow interruptions
- mtcrf 0x40,r7 ; See if we can thermal this machine
- bf pfThermalb,thrmcant ; No can do...
-
- mfspr r11,thrm1 ; Save thrm1
-
-thrmrange: rlwinm r4,r5,31-thrmthre,thrmthrs,thrmthre ; Position it
- ori r4,r4,lo16(thrmtidm|thrmvm) ; Flip on the valid bit and make comparision for less than
-
- mtspr thrm1,r4 ; Set the test value
-
-thrmreada: mfspr r3,thrm1 ; Get the thermal register back
- rlwinm. r0,r3,0,thrmtiv,thrmtiv ; Has it settled yet?
- beq+ thrmreada ; Nope...
-
- rlwinm. r0,r3,0,thrmtin,thrmtin ; Are we still under the threshold?
- bne thrmsearch ; No, we went over...
-
- addi r5,r5,16 ; Start by trying every 16 degrees
- cmplwi r5,127 ; Have we hit the max?
- blt- thrmrange ; Got some more to do...
-
-thrmsearch: rlwinm r4,r5,31-thrmthre,thrmthrs,thrmthre ; Position it
- ori r4,r4,lo16(thrmtidm|thrmvm) ; Flip on the valid bit and make comparision for less than
-
- mtspr thrm1,r4 ; Set the test value
-
-thrmread: mfspr r3,thrm1 ; Get the thermal register back
- rlwinm. r0,r3,0,thrmtiv,thrmtiv ; Has it settled yet?
- beq+ thrmread ; Nope...
-
- rlwinm. r0,r3,0,thrmtin,thrmtin ; Are we still under the threshold?
- beq thrmdone ; No, we hit it...
- addic. r5,r5,-1 ; Go down a degree
- bge+ thrmsearch ; Try again (until we are below freezing)...
-
-thrmdone: addi r3,r5,1 ; Return the temprature (bump it up to make it correct)
- mtspr thrm1,r11 ; Restore the thermal register
- mtmsr r9 ; Re-enable interruptions
- blr ; Leave...
-
-thrmcant: eqv r3,r3,r3 ; Return bogus temprature because we can not read it
- mtmsr r9 ; Re-enable interruptions
- blr ; Leave...
+ li r3,-1
+ blr
/* Throttle processor speed up or down
* unsigned int ml_throttle(unsigned int step)
* Returns old speed and sets new. Both step and return are values from 0 to
* 255 that define number of throttle steps, 0 being off and "ictcfim" is max * 2.
*
+ * Obsolete, deprecated and will be removed.
*/
; Force a line boundry here
.globl EXT(ml_throttle)
LEXT(ml_throttle)
-
- mfmsr r9 ; Save the MSR
- rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
- rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
- rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
- cmplwi r3,lo16(ictcfim>>1) ; See if we are going too far
- mtmsr r8 ; Do not allow interruptions
- isync
- ble+ throtok ; Throttle value is ok...
- li r3,lo16(ictcfim>>1) ; Set max
-
-throtok: rlwinm. r4,r3,1,ictcfib,ictcfie ; Set the throttle
- beq throtoff ; Skip if we are turning it off...
- ori r4,r4,lo16(thrmvm) ; Turn on the valid bit
-
-throtoff: mfspr r3,ictc ; Get the old throttle
- mtspr ictc,r4 ; Set the new
- rlwinm r3,r3,31,1,31 ; Shift throttle value over
- mtmsr r9 ; Restore interruptions
- blr ; Return...
+ li r3,0
+ blr
/*
** ml_get_timebase()
.globl EXT(cpu_number)
LEXT(cpu_number)
- mfsprg r4,0 ; Get per-proc block
+ mfsprg r4,1 ; Get the current activation
+ lwz r4,ACT_PER_PROC(r4) ; Get the per_proc block
lhz r3,PP_CPU_NUMBER(r4) ; Get CPU number
blr ; Return...
+/*
+ * processor_t current_processor(void)
+ *
+ * Returns the current processor.
+ */
+
+ .align 5
+ .globl EXT(current_processor)
+
+LEXT(current_processor)
+ mfsprg r3,1 ; Get the current activation
+ lwz r3,ACT_PER_PROC(r3) ; Get the per_proc block
+ addi r3,r3,PP_PROCESSOR
+ blr
+
+#if PROCESSOR_SIZE > PP_PROCESSOR_SIZE
+#error processor overflows per_proc
+#endif
/*
- * void set_machine_current_act(thread_act_t)
+ * ast_t *ast_pending(void)
*
- * Set the current activation
+ * Returns the address of the pending AST mask for the current processor.
*/
+
.align 5
- .globl EXT(set_machine_current_act)
+ .globl EXT(ast_pending)
-LEXT(set_machine_current_act)
+LEXT(ast_pending)
+ mfsprg r3,1 ; Get the current activation
+ lwz r3,ACT_PER_PROC(r3) ; Get the per_proc block
+ addi r3,r3,PP_PENDING_AST
+ blr ; Return...
+/*
+ * void machine_set_current_thread(thread_t)
+ *
+ * Set the current thread
+ */
+ .align 5
+ .globl EXT(machine_set_current_thread)
+
+LEXT(machine_set_current_thread)
+
+ mfsprg r4,1 ; Get spr1
+ lwz r5,ACT_PER_PROC(r4) ; Get the PerProc from the previous active thread
+ stw r5,ACT_PER_PROC(r3) ; Set the PerProc in the active thread
mtsprg 1,r3 ; Set spr1 with the active thread
blr ; Return...
/*
- * thread_t current_act(void)
* thread_t current_thread(void)
+ * thread_t current_act(void)
*
*
* Return the current thread for outside components.
*/
.align 5
- .globl EXT(current_act)
.globl EXT(current_thread)
+ .globl EXT(current_act)
-LEXT(current_act)
LEXT(current_thread)
+LEXT(current_act)
mfsprg r3,1
blr
mftb r0
mftbu r11
cmpw r11,r9
- bne- 1b
+ bne-- 1b
stw r0,4(r3)
stw r9,0(r3)
blr
mftb r4
mftbu r0
cmpw r0,r3
- bne- 1b
+ bne-- 1b
blr
/*
blr ; Leave...
/*
-** ml_set_processor_speed()
+** ml_set_processor_speed_powertune()
**
*/
; Force a line boundry here
.align 5
- .globl EXT(ml_set_processor_speed)
+ .globl EXT(ml_set_processor_speed_powertune)
+
+LEXT(ml_set_processor_speed_powertune)
+ mflr r0 ; Save the link register
+ stwu r1, -(FM_ALIGN(4*4)+FM_SIZE)(r1) ; Make some space on the stack
+ stw r28, FM_ARG0+0x00(r1) ; Save a register
+ stw r29, FM_ARG0+0x04(r1) ; Save a register
+ stw r30, FM_ARG0+0x08(r1) ; Save a register
+ stw r31, FM_ARG0+0x0C(r1) ; Save a register
+ stw r0, (FM_ALIGN(4*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Save the return
+
+ mfsprg r31,1 ; Get the current activation
+ lwz r31,ACT_PER_PROC(r31) ; Get the per_proc block
+
+ rlwinm r28, r3, 31-dnap, dnap, dnap ; Shift the 1 bit to the dnap+32 bit
+ rlwinm r3, r3, 2, 29, 29 ; Shift the 1 to a 4 and mask
+ addi r3, r3, pfPowerTune0 ; Add in the pfPowerTune0 offset
+ lwzx r29, r31, r3 ; Load the PowerTune number 0 or 1
+
+ sldi r28, r28, 32 ; Shift to the top half
+ ld r3, pfHID0(r31) ; Load the saved hid0 value
+ and r28, r28, r3 ; Save the dnap bit
+ lis r4, hi16(dnapm) ; Make a mask for the dnap bit
+ sldi r4, r4, 32 ; Shift to the top half
+ andc r3, r3, r4 ; Clear the dnap bit
+ or r28, r28, r3 ; Insert the dnap bit as needed for later
+
+ sync
+ mtspr hid0, r3 ; Turn off dnap in hid0
+ mfspr r3, hid0 ; Yes, this is silly, keep it here
+ mfspr r3, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r3, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r3, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r3, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r3, hid0 ; Yes, this is a duplicate, keep it here
+ isync ; Make sure it is set
+
+ lis r3, hi16(PowerTuneControlReg) ; Write zero to the PCR
+ ori r3, r3, lo16(PowerTuneControlReg)
+ li r4, 0
+ li r5, 0
+ bl _ml_scom_write
+
+ lis r3, hi16(PowerTuneControlReg) ; Write the PowerTune value to the PCR
+ ori r3, r3, lo16(PowerTuneControlReg)
+ li r4, 0
+ mr r5, r29
+ bl _ml_scom_write
+
+ rlwinm r29, r29, 13-6, 6, 7 ; Move to PSR speed location and isolate the requested speed
+spsPowerTuneLoop:
+ lis r3, hi16(PowerTuneStatusReg) ; Read the status from the PSR
+ ori r3, r3, lo16(PowerTuneStatusReg)
+ li r4, 0
+ bl _ml_scom_read
+ srdi r5, r5, 32
+ rlwinm r0, r5, 0, 6, 7 ; Isolate the current speed
+ rlwimi r0, r5, 0, 2, 2 ; Copy in the change in progress bit
+ cmpw r0, r29 ; Compare the requested and current speeds
+ beq spsPowerTuneDone
+ rlwinm. r0, r5, 0, 3, 3
+ beq spsPowerTuneLoop
+
+spsPowerTuneDone:
+ sync
+ mtspr hid0, r28 ; Turn on dnap in hid0 if needed
+ mfspr r28, hid0 ; Yes, this is silly, keep it here
+ mfspr r28, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r28, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r28, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r28, hid0 ; Yes, this is a duplicate, keep it here
+ mfspr r28, hid0 ; Yes, this is a duplicate, keep it here
+ isync ; Make sure it is set
+
+ lwz r0, (FM_ALIGN(4*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Get the return
+ lwz r28, FM_ARG0+0x00(r1) ; Restore a register
+ lwz r29, FM_ARG0+0x04(r1) ; Restore a register
+ lwz r30, FM_ARG0+0x08(r1) ; Restore a register
+ lwz r31, FM_ARG0+0x0C(r1) ; Restore a register
+ lwz r1, FM_BACKPTR(r1) ; Pop the stack
+ mtlr r0
+ blr
-LEXT(ml_set_processor_speed)
- mfsprg r5, 0 ; Get the per_proc_info
+/*
+** ml_set_processor_speed_dpll()
+**
+*/
+; Force a line boundry here
+ .align 5
+ .globl EXT(ml_set_processor_speed_dpll)
- cmpli cr0, r3, 0 ; Turn off BTIC before low speed
- beq sps1
- mfspr r4, hid0 ; Get the current hid0 value
- rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit
+LEXT(ml_set_processor_speed_dpll)
+ mfsprg r5,1 ; Get the current activation
+ lwz r5,ACT_PER_PROC(r5) ; Get the per_proc block
+
+ cmplwi r3, 0 ; Turn off BTIC before low speed
+ beq spsDPLL1
+ mfspr r4, hid0 ; Get the current hid0 value
+ rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit
sync
- mtspr hid0, r4 ; Set the new hid0 value
+ mtspr hid0, r4 ; Set the new hid0 value
isync
sync
-sps1:
- mfspr r4, hid1 ; Get the current PLL settings
- rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit
- stw r4, pfHID1(r5) ; Save the new hid1 value
- mtspr hid1, r4 ; Select desired PLL
+spsDPLL1:
+ mfspr r4, hid1 ; Get the current PLL settings
+ rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit
+ stw r4, pfHID1(r5) ; Save the new hid1 value
+ mtspr hid1, r4 ; Select desired PLL
- cmpli cr0, r3, 0 ; Restore BTIC after high speed
- bne sps2
- lwz r4, pfHID0(r5) ; Load the hid0 value
+ cmplwi r3, 0 ; Restore BTIC after high speed
+ bne spsDPLL2
+ lwz r4, pfHID0(r5) ; Load the hid0 value
sync
- mtspr hid0, r4 ; Set the hid0 value
+ mtspr hid0, r4 ; Set the hid0 value
isync
sync
+spsDPLL2:
+ blr
+
+
+/*
+** ml_set_processor_speed_dfs(divideby)
+** divideby == 0 then divide by 1 (full speed)
+** divideby == 1 then divide by 2 (half speed)
+** divideby == 2 then divide by 4 (quarter speed)
+** divideby == 3 then divide by 4 (quarter speed) - preferred
+**
+*/
+; Force a line boundry here
+ .align 5
+ .globl EXT(ml_set_processor_speed_dfs)
-sps2:
+LEXT(ml_set_processor_speed_dfs)
+
+ mfspr r4,hid1 ; Get the current HID1
+ mfsprg r5,0 ; Get the per_proc_info
+ rlwimi r4,r3,31-hid1dfs1,hid1dfs0,hid1dfs1 ; Stick the new divider bits in
+ stw r4,pfHID1(r5) ; Save the new hid1 value
+ sync
+ mtspr hid1,r4 ; Set the new HID1
+ sync
+ isync
blr
+
/*
** ml_set_processor_voltage()
**
.globl EXT(ml_set_processor_voltage)
LEXT(ml_set_processor_voltage)
- mfspr r4, hid2 ; Get HID2 value
- rlwimi r4, r3, 31-hid2vmin, hid2vmin, hid2vmin ; Insert the voltage mode bit
- mtspr hid2, r4 ; Set the voltage mode
- sync ; Make sure it is done
+ mfsprg r5,1 ; Get the current activation
+ lwz r5,ACT_PER_PROC(r5) ; Get the per_proc block
+
+ lwz r6, pfPowerModes(r5) ; Get the supported power modes
+
+ rlwinm. r0, r6, 0, pmDPLLVminb, pmDPLLVminb ; Is DPLL Vmin supported
+ beq spvDone
+
+ mfspr r4, hid2 ; Get HID2 value
+ rlwimi r4, r3, 31-hid2vmin, hid2vmin, hid2vmin ; Insert the voltage mode bit
+ mtspr hid2, r4 ; Set the voltage mode
+ sync ; Make sure it is done
+
+spvDone:
blr
+
+
+;
+; unsigned int ml_scom_write(unsigned int reg, unsigned long long data)
+; 64-bit machines only
+; returns status
+;
+
+ .align 5
+ .globl EXT(ml_scom_write)
+
+LEXT(ml_scom_write)
+
+ rldicr r3,r3,8,47 ; Align register it correctly
+ rldimi r5,r4,32,0 ; Merge the high part of data
+ sync ; Clean up everything
+
+ mtspr scomd,r5 ; Stick in the data
+ mtspr scomc,r3 ; Set write to register
+ sync
+ isync
+
+ mfspr r3,scomc ; Read back status
+ blr ; leave....
+
+;
+; unsigned int ml_read_scom(unsigned int reg, unsigned long long *data)
+; 64-bit machines only
+; returns status
+; ASM Callers: data (r4) can be zero and the 64 bit data will be returned in r5
+;
+
+ .align 5
+ .globl EXT(ml_scom_read)
+
+LEXT(ml_scom_read)
+
+ mfsprg r0,2 ; Get the feature flags
+ rldicr r3,r3,8,47 ; Align register it correctly
+ rlwinm r0,r0,pfSCOMFixUpb+1,31,31 ; Set shift if we need a fix me up
+
+ ori r3,r3,0x8000 ; Set to read data
+ sync
+
+ mtspr scomc,r3 ; Request the register
+ mfspr r5,scomd ; Get the register contents
+ mfspr r3,scomc ; Get back the status
+ sync
+ isync
+
+ sld r5,r5,r0 ; Fix up if needed
+
+ cmplwi r4, 0 ; If data pointer is null, just return
+ beqlr ; the received data in r5
+ std r5,0(r4) ; Pass back the received data
+ blr ; Leave...
+
+;
+; Calculates the hdec to dec ratio
+;
+
+ .align 5
+ .globl EXT(ml_hdec_ratio)
+
+LEXT(ml_hdec_ratio)
+
+ li r0,0 ; Clear the EE bit (and everything else for that matter)
+ mfmsr r11 ; Get the MSR
+ mtmsrd r0,1 ; Set the EE bit only (do not care about RI)
+ rlwinm r11,r11,0,MSR_EE_BIT,MSR_EE_BIT ; Isolate just the EE bit
+ mfmsr r10 ; Refresh our view of the MSR (VMX/FP may have changed)
+ or r12,r10,r11 ; Turn on EE if on before we turned it off
+
+ mftb r9 ; Get time now
+ mfspr r2,hdec ; Save hdec
+
+mhrcalc: mftb r8 ; Get time now
+ sub r8,r8,r9 ; How many ticks?
+ cmplwi r8,10000 ; 10000 yet?
+ blt mhrcalc ; Nope...
+
+ mfspr r9,hdec ; Get hdec now
+ sub r3,r2,r9 ; How many ticks?
+ mtmsrd r12,1 ; Flip EE on if needed
+ blr ; Leave...
+
+
+;
+; int setPop(time)
+;
+; Calculates the number of ticks to the supplied event and
+; sets the decrementer. Never set the time for less that the
+; minimum, which is 10, nor more than maxDec, which is usually 0x7FFFFFFF
+; and never more than that but can be set by root.
+;
+;
+
+ .align 7
+ .globl EXT(setPop)
+
+#define kMin 10
+
+LEXT(setPop)
+
+spOver: mftbu r8 ; Get upper time
+ addic r2,r4,-kMin ; Subtract minimum from target
+ mftb r9 ; Get lower
+ addme r11,r3 ; Do you have any bits I could borrow?
+ mftbu r10 ; Get upper again
+ subfe r0,r0,r0 ; Get -1 if we went negative 0 otherwise
+ subc r7,r2,r9 ; Subtract bottom and get carry
+ cmplw r8,r10 ; Did timebase upper tick?
+ subfe r6,r8,r11 ; Get the upper difference accounting for borrow
+ lwz r12,maxDec(0) ; Get the maximum decrementer size
+ addme r0,r0 ; Get -1 or -2 if anything negative, 0 otherwise
+ addic r2,r6,-1 ; Set carry if diff < 2**32
+ srawi r0,r0,1 ; Make all foxes
+ subi r10,r12,kMin ; Adjust maximum for minimum adjust
+ andc r7,r7,r0 ; Pin time at 0 if under minimum
+ subfe r2,r2,r2 ; 0 if diff > 2**32, -1 otherwise
+ sub r7,r7,r10 ; Negative if duration is less than (max - min)
+ or r2,r2,r0 ; If the duration is negative, it isn't too big
+ srawi r0,r7,31 ; -1 if duration is too small
+ and r7,r7,r2 ; Clear duration if high part too big
+ and r7,r7,r0 ; Clear duration if low part too big
+ bne-- spOver ; Timer ticked...
+ add r3,r7,r12 ; Add back the max for total
+ mtdec r3 ; Set the decrementer
+ blr ; Leave...
+
+