//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/x4clock.s,v 1.6 1996/03/12 14:56:20 pierre Exp $")
// TITLE("Interval and Profile Clock Interrupts")
//++
//
// Copyright (c) 1991 Microsoft Corporation
//
// Module Name:
//
// x4clock.s
//
// Abstract:
//
// This module implements the code necessary to field and process the
// interval and profile clock interrupts on a MIPS R4000 system.
//
// Environment:
//
// Kernel mode only.
//
//
//--
#include "halmips.h"
#include "SNIdef.h"
#define MPA_TIMER_MESSAGE 11 /* timer interrupt */
SBTTL("System Clock Interrupt")
//++
//
// Routine Description:
//
// This routine is entered as the result of an interrupt generated by
// the interval timer. Its function is to acknowledge the interrupt and
// transfer control to the standard system routine to update the system
// time and the execution time of the current thread and process.
//
// Arguments:
//
// s8 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
.struct 0
CiArgs: .space 4 * 4 // saved arguments
.space 3 * 4 // fill
CiRa: .space 4 // saved return address
CiFrameLength: //
NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero)
subu sp,sp,CiFrameLength // allocate stack frame
sw ra,CiRa(sp) // save return address
PROLOGUE_END
move a0,s8 // set address of trap frame
lw a1,HalpCurrentTimeIncrement
lw t0,__imp_KeUpdateSystemTime // update system time
jal t0 //
//
// we use this only when we have the machine up and running ...
// LED's can show us something, what we do not see in the debugger
//
la t0,HalpLedRegister // get current Value of LED Register
lw a0,0(t0)
addu a0,a0,1 // increment
sw a0,0(t0) // store and
lw t0,HalpIsTowerPci
beq t0,zero,2f
jal HalpPciTowerDisplayLed
b 3f
2:
la t0, HalpLedAddress // get address of the variable
lw t0,0(t0) // get value
sb a0,0(t0) // display LSByte (set the LED)
//
// At each clock interrupt the next time increment is moved to the current
// time increment to "pipeline" the update of the current increment at the
// correct time. If the new time increment is nonzero, then the new time
// increment is moved to the next time increment and the timer is reprogramed
//
3: lw t0,KdDebuggerEnabled // get address of debugger enable
lw t1,HalpNewTimeIncrement // get new time increment
lw t2,HalpNextTimeIncrement // get the next increment value
lbu t0,0(t0) // get debugger enable flag
lw ra,CiRa(sp) // restore return address
or t4,t1,t0 // new interval count or debugger?
sw t2,HalpCurrentTimeIncrement // pipeline current increment value
bne zero,t4,10f // if ne, interval change or debugger
addu sp,sp,CiFrameLength // deallocate stack frame
j ra // return
//
// The interval count must be changed or the debugger is enabled.
//
10: sw zero,HalpNewTimeIncrement // clear new time increment
beq zero,t1,15f // if eq, not interval count change
sw t1,HalpNextTimeIncrement // set next time increment value
move a0,t1 // prepare to call HalpProgramIntervalTimer
jal HalpProgramIntervalTimer // program timer chip ...
15: beq zero,t0,40f // if eq, debugger not enabled
jal KdPollBreakIn // check if breakin is requested
beq zero,v0,40f // if eq, no breakin requested
break BREAKIN_BREAKPOINT // break into the debugger
40: lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j ra // return
.end HalpClockInterrupt
SBTTL("System Clock Interrupt - Processor N")
//++
//
// Routine Description:
//
// This routine is entered as the result of an interrupt generated by
// the extra interval timer in the slave processors. Its function is
// to transfer control to the standard system routine to update the
// execution time of the current thread and process.
//
// Note: We plan to use the extra timer for our MultiProcessor (SNI)Machine
// MAYBE, if we have arbitrated interrupts, we have to acknowledge
// this interrupt here and send an message to the other processors
// (Quadro machine)
//
// Arguments:
//
// s8 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(HalpClockInterrupt1, CiFrameLength, zero)
subu sp,sp,CiFrameLength // allocate stack frame
sw ra,CiRa(sp) // save return address
PROLOGUE_END
li a0,0x1000
jal HalpCheckSpuriousInt
beq v0,0,10f
lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j ra
10:
li t0, PCI_EXTRA_TIMER_ACK_ADDR // get address of acknowledge register
sb zero,0(t0) // acknowledge timer interrupt
move a0,s8 // set address of trap frame
lw t1,__imp_KeUpdateRunTime // update system runtime
lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j t1 //
.end HalpClockInterrupt1
SBTTL("System Clock Interrupt - Processor N")
//++
//
// Routine Description:
//
// This routine is entered as the result of an interrupt generated by
// the extra interval timer in the slave processors. Its function is
// to transfer control to the standard system routine to update the
// execution time of the current thread and process.
//
// We use the extra timer for our MultiProcessor (SNI)Machine
// we have to acknowledge
// this interrupt here and send an message to the other processors
// (Quadro machine)
//
// Arguments:
//
// s8 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(HalpClockInterruptPciTower, CiFrameLength, zero)
subu sp,sp,CiFrameLength // allocate stack frame
sw ra,CiRa(sp) // save return address
PROLOGUE_END
//
// Send a "TIMER" ipi
//
lw a0,HalpIsMulti // test if more than 2 procs
li a1,2
slt a2,a1,a0
beq a2,0,10f // if no more than 2 proc , no need to send Ipi
li a0,0xc // send IPI to proc 2 and 3
li a1,MPA_TIMER_MESSAGE
jal HalpRequestIpi
10: move a0,s8 // set address of trap frame
lw t1,__imp_KeUpdateRunTime // update system runtime
lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j t1 //
.end HalpClockInterruptPciTower
SBTTL("Profile Clock Interrupt")
//++
//
// Routine Description:
//
// This routine is entered as the result of an interrupt generated by the
// profile clock. Its function is to acknowledge the profile interrupt,
// compute the next compare value, update the performance counter, and
// transfer control to the standard system routine to process any active
// profiles.
//
// Arguments:
//
// s8 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
NESTED_ENTRY(HalpProfileInterrupt, CiFrameLength, zero)
subu sp,sp,CiFrameLength // allocate stack frame
sw ra,CiRa(sp) // save return address
PROLOGUE_END
// li a0,0x8000
// jal HalpCheckSpuriousInt
// beq v0,zero,10f
// lw ra,CiRa(sp) // restore return address
// addu sp,sp,CiFrameLength // deallocate stack frame
// j ra
10: .set noreorder
.set noat
mfc0 t1,count // get current count value
mfc0 t0,compare // get current comparison value
addu t1,t1,8 // factor in lost cycles
subu t1,t1,t0 // compute initial count value
mtc0 t0,compare // dismiss interrupt
mtc0 t1,count // set new count register value
.set at
.set reorder
//
// we prefer the MultiPro version, which also works on UniPro machines
//
lw t1,KiPcr + PcPrcb(zero) // get current processor block address
la t2,HalpPerformanceCounter // get performance counter address
lbu t1,PbNumber(t1) // get processor number
sll t1,t1,3 // compute address of performance count
addu t1,t1,t2 //
lw t2,LiLowPart(t1) // get low part of performance count
lw t3,LiHighPart(t1) // get high part of performance count
addu t2,t2,t0 // update low part of performance count
sw t2,LiLowPart(t1) // store low part of performance count
sltu t4,t2,t0 // generate carry into high part
addu t3,t3,t4 // update high part of performance count
sw t3,LiHighPart(t1) // store high part of performance count
li a0,0x00
move a0,s8 // set address of trap frame
lw t4,__imp_KeProfileInterrupt // process profile interrupt
jal t4 //
jal HalpCheckSpuriousInt
lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j ra
.end HalpProfileInterrupt
SBTTL("Read Count Register")
//++
//
// ULONG
// HalpReadCountRegister (
// VOID
// );
//
// Routine Description:
//
// This routine reads the current value of the count register and
// returns the value.
//
// Arguments:
//
// None.
//
// Return Value:
//
// Current value of the count register.
//
//--
LEAF_ENTRY(HalpReadCountRegister)
.set noreorder
.set noat
mfc0 v0,count // get count register value
.set at
.set reorder
j ra // return
.end HalpReadCountRegister
SBTTL("Write Compare Register And Clear")
//++
//
// ULONG
// HalpWriteCompareRegisterAndClear (
// IN ULONG Value
// );
//
// Routine Description:
//
// This routine reads the current value of the count register, writes
// the value of the compare register, clears the count register, and
// returns the previous value of the count register.
//
// Arguments:
//
// Value - Supplies the value written to the compare register.
//
// Return Value:
//
// Previous value of the count register.
//
//--
LEAF_ENTRY(HalpWriteCompareRegisterAndClear)
.set noreorder
.set noat
mfc0 v0,count // get count register value
mtc0 a0,compare // set compare register value
li t0,7 // set lost cycle count
mtc0 t0,count // set count register to zero
.set at
.set reorder
j ra // return
.end HalpWriteCompareRegisterAndClear
NESTED_ENTRY(HalpPciTowerDisplayLed, CiFrameLength, zero)
subu sp,sp,CiFrameLength // allocate stack frame
sw ra,CiRa(sp) // save return address
PROLOGUE_END
//
// code for PCI tower
//
li t5,8,
divu a0,t5
mfhi t4
li t5,1
.word 0x018d2004 # sllv a0,t5,t4
// t4 -> temp-reg.
// t5 -> low-reg. 32 bits
// t6 -> high-reg. 32 bits
and t5,a0,0x01 # bit0 shift to bit0(LED0)
and t4,a0,0x02 # bit1 shift to bit16(LED1)
sll t4,t4,16-1
or t5,t5,t4
and t4,a0,0x04 # bit2 shift to bit32(LED2) -> bit0/high_reg.
srl t6,t4,2-0
and t4,a0,0x08 # bit3 shift to bit48(LED3) -> bit16/high_reg.
sll t4,t4,16-3
or t6,t6,t4
and t4,a0,0x10 # bit4 shift to bit1(LED4)
srl t4,t4,4-1
or t5,t5,t4
and t4,a0,0x20 # bit5 shift to bit17(LED5)
sll t4,t4,17-5
or t5,t5,t4
and t4,a0,0x40 # bit6 shift to bit33(LED6) -> bit1/high_reg.
srl t4,t4,6-1
or t6,t6,t4
and t4,a0,0x80 # bit7 shift to bit49(LED7) -> bit17/high_reg.
sll t4,t4,17-7
or t6,t6,t4
lw a1,HalpLedAddress
lw t4,0(a1)
and t4,t4,PCI_TOWER_LED_MASK # led mask
or t4,t4,t5 # t5 -> low 32 bits
sw t4,0(a1)
jal KeFlushWriteBuffer
lw a1,HalpLedAddress
lw t4,4(a1)
and t4,t4,PCI_TOWER_LED_MASK # led mask
or t4,t4,t6 # t6 -> high 32 bits
sw t4,4(a1)
jal KeFlushWriteBuffer
lw ra,CiRa(sp) // restore return address
addu sp,sp,CiFrameLength // deallocate stack frame
j ra
.end HalpPciTowerDisplayLed
//
// end code for PCI 1tower
//