NT4/private/ntos/nthals/halr98b/mips/rxdspt.c
2020-09-30 17:12:29 +02:00

548 lines
19 KiB
C

/*++
Copyright (c) 1994 Kobe NEC Software
Module Name:
rxdspt.c
Abstract:
This module implements the interrupt dispatch routines for R98
Author:
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "bugcodes.h"
//
// Define the context structure for use by the interrupt routine.
//
typedef BOOLEAN (*PSECONDARY_DISPATCH)(
PVOID InterruptRoutine
);
typedef BOOLEAN (*PTIMER_DISPATCH)(
ULONG TrapFrame
);
//
// Dummy Read Registers
//
//
volatile ULONG DUMMYADDRS[]={
0x1c0003f1|KSEG1_BASE, //FDC37C665 config register
0x1c4033c7|KSEG1_BASE, //VGA DAC STATE register
0x1c0003f1|KSEG1_BASE, //FDC37C665 config register
0x1c000023|KSEG1_BASE, //ESC Configuration register
0x1c4033c7|KSEG1_BASE, //VGA DAC STATE register
0x19800610|KSEG1_BASE //Err node register
};
//
// Following structures will be changed by HalAllProcessorsStarted() on
// boot up HAL.
// Because each interrupt connects each processor on boot up HAL.
// v-masank@microsoft.com
//
INT_ENTRY HalpIntEntry[R98_CPU_NUM_TYPE][R98B_MAX_CPU][NUMBER_OF_INT]={
{// For R4400 [CPU][INT x] {StartBit, NumberOfBit,Arbitar,Enable,Open}
{ // For CPU #0
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 16 ,0,(ULONGLONG)0x00000000e3f00000,0}, //INT1
{32, 12 ,0,(ULONGLONG)0x000000f800000000,0}, //INT2
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT3
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT4
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0} //INT5
},
{ // For CPU #1
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 16 ,0,(ULONGLONG)0x00000000e3f00000,0}, //INT1
{32, 12 ,0,(ULONGLONG)0x000000f800000000,0}, //INT2
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT3
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT4
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0} //INT5
},
{ // For CPU #2
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 16 ,0,(ULONGLONG)0x00000000e3f00000,0}, //INT1
{32, 12 ,0,(ULONGLONG)0x000000f800000000,0}, //INT2
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT3
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT4
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0} //INT5
},
{ // For CPU #3
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 16 ,0,(ULONGLONG)0x00000000e3f00000,0}, //INT1
{32, 12 ,0,(ULONGLONG)0x000000f800000000,0}, //INT2
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT3
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT4
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0} //INT5
}
},
{// For R10000 [CPU][INT x] {StartBit, NumberOfBit,Arbitar,Enable,Open}
{
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 28 ,0,(ULONGLONG)0x000000f8e3f00000,0}, //INT1
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT2
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT3
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0}, //INT4
{NONE, 0 ,0,(ULONGLONG)0,0} //INT5
},
{
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 28 ,0,(ULONGLONG)0x000000f8e3f00000,0}, //INT1
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT2
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT3
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0}, //INT4
{NONE, 0 ,0,(ULONGLONG)0,0} //INT5
},
{
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 28 ,0,(ULONGLONG)0x000000f8e3f00000,0}, //INT1
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT2
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT3
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0}, //INT4
{NONE, 0 ,0,(ULONGLONG)0,0} //INT5
},
{
{0, 16 ,0,(ULONGLONG)0x000000000000e1b6,0}, //INT0
{16, 28 ,0,(ULONGLONG)0x000000f8e3f00000,0}, //INT1
{56, 2 ,0,(ULONGLONG)0x0300000000000000,0}, //INT2
{48, 4 ,0,(ULONGLONG)0x000f000000000000,0}, //INT3
{61, 2 ,0,(ULONGLONG)0x6000000000000000,0}, //INT4
{NONE, 0 ,0,(ULONGLONG)0,0} //INT5
}
}
};
RESET_REGISTER HalpResetValue[NUMBER_OF_IPR_BIT]={
{0,0,0,0}, //Bit 0
{PONCE1,PCIINTD,0,DUMMY_A4}, //Bit 1 PCI I/O Slot#8-#10 INTD
{PONCE0,PCIINTD,0,DUMMY_A3}, //Bit 2 PCI I/O Slot#4-#7 INTD
{0x0,0x0,0,0}, //Bit 3
{PONCE1,PCIINTC,0,DUMMY_A4}, //Bit 4 PCI I/O Slot#8-#10 INTC
{PONCE0,PCIINTC,0,DUMMY_A3}, //Bit 5 PCI I/O Slot#4-#7 INTC
{0x0,0x0,0,0} , //Bit 6
{PONCE1,PCIINTB,0,DUMMY_A4}, //Bit 7 PCI I/O Slot#8-#10 INTB
{PONCE0,PCIINTB,0,DUMMY_A3}, //Bit8 PCI I/O Slot#4-#7 INTB
{0x0,0x0,0,0}, //Bit9
{0x0,0x0,0,0}, //Bit10
{0x0,0x0,0,0}, //Bit11
{0x0,0x0,0,0}, //Bit12
{PONCE0,INTSA0,0x0,DUMMY_A3}, //Bit13 EISA Bridge
{PONCE1,INTSB0,0x0,DUMMY_A2}, //Bit14 Parallel
{PONCE0,INTSB0,0x0,DUMMY_A2}, //Bit15 FDC
{0x0,0x0,0,0}, //Bit16
{0x0,0x0,0,0}, //Bit17
{0x0,0x0,0,0}, //Bit18
{0x0,0x0,0,0}, //Bit19
{PONCE1,PCIINTA1,0x0,DUMMY_A4}, //Bit20 PCI I/O Slot#8 INTA
{PONCE1,PCIINTA0,0x0,DUMMY_A4}, //Bit21 PCI I/O Slot#9 INTA
{PONCE0,PCIINTA3,0x0,DUMMY_A3}, //Bit22 PCI I/O Slot#4 INTA
{PONCE0,PCIINTA2,0x0,DUMMY_A3}, //Bit23 PCI I/O Slot#5 INTA
{PONCE0,PCIINTA1,0,DUMMY_A3}, //Bit24 PCI I/O Slot#6 INTA
{PONCE0,PCIINTA0,0,DUMMY_A3}, //Bit25 PCI I/O Slot#7 INTA
{0x0,0x0,0,0}, //Bit26
{0x0,0x0,0,0}, //Bit27
{0x0,0x0,0,0}, //Bit28
{PONCE1,INTSA0,0x0,DUMMY_A1}, //Bit29 LAN(Ethernet)
{PONCE1,PCIINTA3,0x0,DUMMY_A1}, //Bit30 SCSI#1(Narrow)
{PONCE1,PCIINTA2,0x0,DUMMY_A1}, //Bit31 SCSI#0(Wide)
{0x0,0x0,0,0}, //Bit32
{0x0,0x0,0,0}, //Bit33
{0x0,0x0,0,0}, //Bit34 Tracer ponce Internal
{0x0,0x0,0,0}, //Bit35 TLB Undefine Address
{PONCE1,INTSB1,0,DUMMY_A0}, //Bit36 Mouse
{PONCE1,INTSA1,0,DUMMY_A0}, //Bit37 KeyBoard
{PONCE0,INTSB1,0,DUMMY_A0}, //Bit38 SIO#1
{PONCE0,INTSA1,0,DUMMY_A0}, //Bit39 SIO#0
{ RFU,0,0,0}, //Bit40
{ RFU,0,0,0}, //Bit41
{ RFU,0,0,0}, //Bit42
{ RFU,0,0,0}, //Bit43
// Never Used This is no Device Interrupt.
{ RFU,0,0,0}, //Bit44
{ RFU,0,0,0}, //Bit45
{ RFU,0,0,0}, //Bit46
{ RFU,0,0,0}, //Bit47
{ RFU,0,0,0}, //Bit48 From CPU#3 IPI
{ RFU,0,0,0}, //Bit49 From CPU#2 IPI
{ RFU,0,0,0}, //Bit50 From CPU#1 IPI
{ RFU,0,0,0}, //Bit51 From CPU#0 IPI
{ RFU,0,0,0}, //Bit52
{ RFU,0,0,0}, //Bit53
{ RFU,0,0,0}, //Bit54
{ RFU,0,0,0}, //Bit55
{ RFU,0,0,0}, //Bit56 Interval timer 2 Profile
{ RFU,0,0,0}, //Bit57 Interval timer 1 Clock
{ RFU,0,0,0}, //Bit58
{ RFU,0,0,0}, //Bit59
{ RFU,0,0,0}, //Bit60
{ RFU,0,0,0}, //Bit61 EIF+MRCINT
{ RFU,0,0,0}, //Bit62 Memory 1Bit Error
{ RFU,0,0,0} //Bit63
};
// Thanks very much for pete-san's cooporation.
// Pete-san write most of following source code.
// v-masak@microsoft.com
// 5/17/96
#define HalpFindFirstSetMember(Set) \
((Set & 0xFF) ? HalpFindFirstSet[Set & 0xFF] : \
((Set & 0xFF00) ? HalpFindFirstSet[(Set >> 8) & 0xFF] + 8 : \
((Set & 0xFF0000) ? HalpFindFirstSet[(Set >> 16) & 0xFF] + 16 : \
HalpFindFirstSet[(Set >> 24) & 0xff] + 24)))
ULONG HalpFindFirstSet[256] = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
PINT_ENTRY HalpIntEntryPointer;
//
// I use LargeReigester access function for performance
// v-masank@microsoft.com
// I used 64 bit shift.
// v-masank@microsoft.com
//
VOID
HalpGeneralDispatch(
IN ULONG TrapFrame,
IN ULONG IntNo
)
/*++
Routine Description:
This is the general hal interrupt dispatch routine. This services hardware interrupts
for range ip[3..8]
Arguments:
IN ULONG TrapFrame - This interrupts trapframe
IN ULONG IntNo - The current Interrupt Number range IntNo[0..5] maps to IP[3..8]
Return Value:
None.
--*/
{
volatile PULONGLONG Register;
ULONGLONG Enable;
volatile ULONGLONG IPR;
ULONGLONG IprBit;
ULONG ULIPR;
ULONG CpuNumber;
ULONG cnt;
ULONG IprBitNumber;
ULONG Ponce;
UCHAR Data;
ULONG StartBit;
//
// Get CpuNumber
//
CpuNumber = PCR->Number;
//
// Get Enable table offset
//
cnt = CpuNumber * NUMBER_OF_INT;
//
// The interrupt controller on the R98A/B occasionally (rarely) sends
// an interrupt to multiple processors. One is the correct processor to
// handle the interrupt the other is not. The enable bit
// determines if this processor handles this interrupt.
//
// The table HalpIntEntryPointer gets initalized for the correct processor at boot
// (i.e., R98A or R98B).
Enable=HalpIntEntryPointer[cnt+IntNo].Enable;
StartBit = HalpIntEntryPointer[cnt+IntNo].StartBitNo;
//
// Do until no more interrupts pending
//
do {
//
// IPR register read
//
Register = (PULONGLONG)&((COLUMNBS_LCNTL)->IPR);
HalpReadLargeRegister(Register,(PULONGLONG)&IPR);
// MASK
//
// Determine if this Interrupt enabled for this processor
//
IPR = IPR & Enable;
//
// 28 is the largest interrupt bit vector possible on these machines
// StartBit is the starting bit position for this interrupt level
// Shift the 64 bit interrupt register into a 32 bit field
// to make the find first bit set operation easier
ULIPR = (ULONG) (IPR >> StartBit);
if(ULIPR==0){
continue; // No interrupts handled by this processor
}
do{
//
// Service all pending interrupts for this ip level
//
while(ULIPR!=0){
//
// Get Interrupt bit set No. on IPR.
//
IprBitNumber = HalpFindFirstSetMember(ULIPR) + StartBit;
IprBit = 1UI64 << IprBitNumber; // Save this value for clearing INT
//
// IPR register read
// IntNo 0 1 2 3 4 5
//
// R98A Starting bit pos 0 16 32 56 48 61
// R98B Starting bit pos 0 16 56 48 61 NA
//
// On the R98A/B Each interrupt level can have multiple
// concurrentinterrupt sources
// (e.g., the read of IPR can have more than 1 bit set
//
//
// Hardware Ip #of possible interrupt sources
// R98A R98B
// ip[3] 16 16
// ip[4] 16 28
// ip[5] 12 2
// ip[6] 2 4
// ip[7] 4 2
// ip[8] 2 0
//
// During initialization the HAL assigns affinity to interrupt sources. So that
// the interrupt always gets serviced on the same processor
switch (IprBitNumber) {
case 62:
//
// call Ecc Error service routine
//
((PSECONDARY_DISPATCH)PCR->InterruptRoutine[62+DEVICE_VECTORS])
(PCR->InterruptRoutine[62+DEVICE_VECTORS]);
//
// Clear IPR
//
Register=(PULONGLONG) &((COLUMNBS_LCNTL)->IPRR);
HalpWriteLargeRegister(Register,&IprBit);
break;
case 61:
//
// This interrupt gets sent to all processors.
// Our friend the HalpDieLock controls exclusive access
// protecting the power switch interrupt service routine
// and for some reason the read/write of the Power interrupt
// register.
//
//
KiAcquireSpinLock(&HalpDieLock);
//
// It's EIF or MRC INT
//
((PSECONDARY_DISPATCH)PCR->InterruptRoutine[61+DEVICE_VECTORS])
(PCR->InterruptRoutine[61+DEVICE_VECTORS]);
// HACK HACK HACK !!
HalpLocalDeviceReadWrite(MRCINT,&Data,LOCALDEV_OP_READ);
if( Data & 0x04){
//
// At This time If MRCINT Register reported Power Interrupt.
// Power Driver failed or happenig ocurred.
// if anyone push DUMP KEY. Hal may be system reset.
// So Reset Power Interrupt.
//
Data = 0x0;
HalpLocalDeviceReadWrite(MRCINT, &Data, LOCALDEV_OP_WRITE);
}
KiReleaseSpinLock(&HalpDieLock);
//
//Clear IPR
//
Register= (PULONGLONG) &(COLUMNBS_LCNTL)->IPRR;
HalpWriteLargeRegister(Register,&IprBit);
break;
case 56:
case 57:
//
// Profile or Clock
//
((PTIMER_DISPATCH)PCR->InterruptRoutine[IprBitNumber+DEVICE_VECTORS])(TrapFrame);
//
//Clear IPR
//
Register= (PULONGLONG)&(COLUMNBS_LCNTL)->IPRR;
HalpWriteLargeRegister(Register,&IprBit);
break;
case 48:
case 49:
case 50:
case 51:
//
// Clear IPR
//
Register= (PULONGLONG) &(COLUMNBS_LCNTL)->IPRR;
HalpWriteLargeRegister(Register,&IprBit);
//
// IPI interrupts. One for each possible CPU
//
((PTIMER_DISPATCH) PCR->InterruptRoutine[IprBitNumber+DEVICE_VECTORS])(TrapFrame);
break;
default:
//
// Device Interrupt !!
//
Ponce = HalpResetValue[IprBitNumber].Ponce;
//
// 1. Clear INTRG register of PONCE
//
WRITE_REGISTER_ULONG((PULONG)&PONCE_CNTL(Ponce)->INTRG,
0x1 << HalpResetValue[IprBitNumber].IntGResetBit);
//
// 2. Call interrupt service routine
//
((PSECONDARY_DISPATCH)PCR->InterruptRoutine[IprBitNumber+DEVICE_VECTORS])(
PCR->InterruptRoutine[IprBitNumber+DEVICE_VECTORS]);
//
// 3. Dummy Read execute
//
READ_REGISTER_UCHAR( DUMMYADDRS[HalpResetValue[IprBitNumber].Dummy]);
READ_REGISTER_UCHAR( DUMMYADDRS[HalpResetValue[IprBitNumber].Dummy]);
//
// 4. Clear IPR Bit By IPRR Register
//
Register = (PULONGLONG) &(COLUMNBS_LCNTL)->IPRR;
HalpWriteLargeRegister(Register,&IprBit);
//
// 5.Clear INTRG register of PONCE
//
WRITE_REGISTER_ULONG((PULONG)&PONCE_CNTL(Ponce)->INTRG,
0x1 << (HalpResetValue[IprBitNumber].IntGResetBit + 21));
} // End Switch
//
// Clear the bit in the interrupt register
// that we just serviced
//
ULIPR = ULIPR & ~(1 << (IprBitNumber - StartBit));
} // End while servicing current interrupt. Check for more
//
// Determine if another interrupt pending at the same level before leaving
// this dispatch routine. The hardware spec implies that there is
// a small window that the interrupt register has bits set before the
// cause register. So it suggests checking the interrupt register
// before the cause
//
//
// check new interrupt
//
//
// IPR register read
//
Register = (PULONGLONG)&((COLUMNBS_LCNTL)->IPR);
HalpReadLargeRegister(Register,(PULONGLONG)&IPR);
// MASK
//
// Determine if this Interrupt enabled for this processor
//
IPR = IPR & Enable;
ULIPR = (ULONG) (IPR >> StartBit);
}while(ULIPR!=0); // End do-while
//
// Check cause register to see if an interrupt pending for the current level
//
} while(HalpGetCause() & (1 << CAUSE_INT_PEND_BIT+IntNo));
}