+
+
+;
+; 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 is not 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...
+
+