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

1308 lines
45 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/r4intdsp.c,v 1.9 1996/02/23 17:55:12 pierre Exp $")
/*++
Copyright (c) 1993 - 1994 Siemens Nixdorf Informationssysteme AG
Module Name:
r4intdsp.c
Abstract:
This module contains the HalpXxx routines which are important to
handle the Interrupts on the SNI machines.
Environment:
Kernel mode
--*/
#include "halp.h"
#include "SNIregs.h"
#include "mpagent.h"
#include "eisa.h"
#include "pci.h"
//
// Define the context structure for use by the interrupt routine.
//
typedef BOOLEAN (*PSECONDARY_DISPATCH)(
PVOID InterruptRoutine
);
typedef BOOLEAN (*PINT0_DISPATCH)(
PKINTERRUPT Interupt,
PVOID ServiceContext
);
extern VOID HalpSendIpi(IN ULONG pcpumask, IN ULONG msg_data);
KINTERRUPT HalpInt0Interrupt; // Interrupt Object for SC machines (centralised interrupt)
KINTERRUPT HalpInt3Interrupt; // Interrupt Object for IT3 tower multipro
ULONG HalpTargetRetryCnt=0; // Counter for pci error ( initiator receives target retry)
ULONG HalpSingleEccCounter = 0; // Single Ecc Error Counter (for RM200/RM300)
extern VOID
HalpReadPCIConfig (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
extern VOID
HalpWritePCIConfig (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
extern BOOLEAN
HalpPciEisaDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
) ;
extern BOOLEAN
HalpPciEisaSBDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
) ;
extern BOOLEAN HalpESC_SB;
BOOLEAN
HalpCreateIntPciStructures (
VOID
)
/*++
Routine Description:
This routine initializes the structures necessary for Int0-handling
and connects the intermediate interrupt dispatcher.
Also the structures necessary for PCI tower Int3 (MAUI interrupt)
Arguments:
None.
Return Value:
If the second level interrupt dispatcher are connected, then a value of
TRUE is returned. Otherwise, a value of FALSE is returned.
--*/
{
PVOID InterruptSourceRegister;
PINT0_DISPATCH (DispatchRoutine);
PKSPIN_LOCK pSpinLock;
switch (HalpMainBoard) {
case M8150 : InterruptSourceRegister = (PVOID)PCI_TOWER_INTERRUPT_SOURCE_REGISTER;
DispatchRoutine = HalpPciTowerInt0Dispatch;
pSpinLock = (PKSPIN_LOCK)NULL;
break;
default: InterruptSourceRegister = (PVOID)PCI_INTERRUPT_SOURCE_REGISTER;
DispatchRoutine = HalpPciInt0Dispatch;
pSpinLock = &HalpInterruptLock;
}
KeInitializeInterrupt( &HalpInt0Interrupt,
DispatchRoutine,
InterruptSourceRegister,
(PKSPIN_LOCK)pSpinLock,
INT0_LEVEL,
INT0_LEVEL, //INT0_LEVEL,
INT0_LEVEL, //Synchr. Level
LevelSensitive,
FALSE, // only one Intobject ispossible for int0
0, // processor number
FALSE // floating point registers
// and pipe line are not
// saved before calling
// the service routine
);
if (!KeConnectInterrupt( &HalpInt0Interrupt )) {
//
// this is the central Interrupt for the SNI SecondLevel Cache Machines
//
HalDisplayString("Failed to connect Int0!\n");
return(FALSE);
}
return (TRUE);
}
BOOLEAN
HalpCreateIntPciMAUIStructures (
CCHAR Number
)
/*++
Routine Description:
This routine initializes the structures necessary
for PCI tower Int3 (MAUI interrupt)
Arguments:
None.
Return Value:
If the second level interrupt dispatcher are connected, then a value of
TRUE is returned. Otherwise, a value of FALSE is returned.
--*/
{
PVOID InterruptSourceRegister;
InterruptSourceRegister = (PVOID)PCI_TOWER_INTERRUPT_SOURCE_REGISTER;
KeInitializeInterrupt( &HalpInt3Interrupt,
HalpPciTowerInt3Dispatch,
InterruptSourceRegister,
(PKSPIN_LOCK)&HalpInterruptLock,
INT6_LEVEL,
INT6_LEVEL, //INT6_LEVEL,
INT6_LEVEL, //Synchr. Level
LevelSensitive,
FALSE, // only one Intobject ispossible for int0
Number, // processor number
FALSE // floating point registers
// and pipe line are not
// saved before calling
// the service routine
);
if (!KeConnectInterrupt( &HalpInt3Interrupt )) {
//
// this is the central Interrupt for the SNI SecondLevel Cache Machines
//
HalDisplayString("Failed to connect Int3!\n");
return(FALSE);
}
}
BOOLEAN
HalpPciInt0Dispatch (
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This routine handles the central INT0 Interrupt on an SNI PCI Desktop or Minitower
To decide which interrupt, read the Interrupt Source Register
We have to manage priorities by software.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - Supplies a pointer to the Interrupt
Source register.
Return Value:
A BOOLEAN value, TRUE if the interrupt is OK,
otherwise FALSE for unknown interrupts
--*/
{
UCHAR IntSource;
UCHAR MaStatus;
ULONG Itpend;
BOOLEAN SCSIresult, NETresult, result;
if (HalpCheckSpuriousInt(0x400)) return(FALSE);
IntSource = READ_REGISTER_UCHAR(ServiceContext);
IntSource ^= PCI_INTERRUPT_MASK; // XOR the low active bits with 1 gives 1
// and XOR the high active with 0 gives 1
if ( IntSource & PCI_EISA_MASK) { // EISA Interrupt
if (HalpESC_SB)
result = HalpPciEisaSBDispatch( NULL, // InterruptObject (unused)
(PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
);
else
result = HalpPciEisaDispatch( NULL, // InterruptObject (unused)
(PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
);
HalpCheckSpuriousInt(0x00);
return(result);
}
//
// look for SCSI Interrupts
//
if ( IntSource & PCI_SCSI_MASK){
SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI_VECTOR])(
PCR->InterruptRoutine[SCSI_VECTOR]
);
#if DBG
if(!SCSIresult) DebugPrint(("Got an invalid SCSI interrupt !\n"));
#endif
HalpCheckSpuriousInt(0x00);
return(SCSIresult);
}
//
// PCI interrupts
//
if ( IntSource & PCI_INTA_MASK){
int i;
for (i=INTA_VECTOR;i<HalpIntAMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_INTB_MASK){
int i;
for (i=INTB_VECTOR;i<HalpIntBMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_INTC_MASK){
int i;
for (i=INTC_VECTOR;i<HalpIntCMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_INTD_MASK){
int i;
for (i=INTD_VECTOR;i<HalpIntDMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
//
// look for an Ethernet Interrupt
//
if ( IntSource & PCI_NET_MASK){
NETresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[NET_LEVEL])(
PCR->InterruptRoutine[NET_LEVEL]
);
HalpCheckSpuriousInt(0x00);
return(NETresult);
}
//
// Other interrupts => look in MSR register
//
if ( IntSource & PCI_INT2_MASK) {
MaStatus = READ_REGISTER_UCHAR(PCI_MSR_ADDR);
if (HalpMainBoard == DesktopPCI) {
MaStatus ^= PCI_MSR_MASK_D;
} else {
MaStatus ^= PCI_MSR_MASK_MT;
}
//
// look for an ASIC interrupt
//
if ( MaStatus & PCI_MSR_ASIC_MASK){
Itpend = READ_REGISTER_ULONG(PCI_ITPEND_REGISTER);
if ( Itpend & (PCI_ASIC_ECCERROR | PCI_ASIC_TRPERROR)) {
ULONG ErrAddr, AsicErrAddr, Syndrome, ErrStatus, irqsel;
AsicErrAddr = ErrAddr = READ_REGISTER_ULONG(PCI_ERRADDR_REGISTER);
Syndrome = READ_REGISTER_ULONG(PCI_SYNDROME_REGISTER);
Syndrome &= 0xff; // only 8 lower bits are significant
ErrStatus = READ_REGISTER_ULONG(PCI_ERRSTATUS_REGISTER);
if (ErrStatus & PCI_MEMSTAT_PARERR) {
// Parity error (PCI_ASIC <-> CPU)
irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER);
WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER ,
(irqsel & 0x70000)); // PARERR it not routed
ErrAddr = HalpFindEccAddr(AsicErrAddr,(PVOID)PCI_ERRSTATUS_REGISTER,(PVOID)PCI_MEMSTAT_PARERR);
if (ErrAddr == -1) ErrAddr = AsicErrAddr;
#if DBG
DebugPrint(("pci_memory_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n",
ErrStatus,ErrAddr,Syndrome));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 1;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PARITY ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome);
#endif
}
if (ErrStatus & PCI_MEMSTAT_ECCERR) {
// ECC error (PCI_ASIC <-> Memory access)
AsicErrAddr &= 0xfffffff8;
irqsel = READ_REGISTER_ULONG(PCI_IRQSEL_REGISTER);
WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER ,
(irqsel & 0xe000)); // ECC it not routed
ErrAddr = HalpFindEccAddr(AsicErrAddr,(PVOID)PCI_ERRSTATUS_REGISTER,(PVOID)PCI_MEMSTAT_ECCERR);
if (ErrAddr == -1) ErrAddr = AsicErrAddr;
if (ErrStatus & PCI_MEMSTAT_ECCSINGLE) {
// HalSweepDcacheRange(0x80000000,2*(PCR->FirstLevelDcacheSize)); // to avoid data_coherency_exception
// HalSweepIcacheRange(0x80000000,2*(PCR->FirstLevelIcacheSize)); // to avoid data_coherency_exception
if (HalpProcessorId == MPAGENT)
HalpMultiPciEccCorrector(ErrAddr,ErrAddr >> PAGE_SHIFT,4);
else
HalpPciEccCorrector(ErrAddr,ErrAddr >> PAGE_SHIFT,4);
// HalSweepDcacheRange(0x80000000,2*(PCR->FirstLevelDcacheSize)); // to avoid data_coherency_exception
// HalSweepIcacheRange(0x80000000,2*(PCR->FirstLevelIcacheSize)); // to avoid data_coherency_exception
WRITE_REGISTER_ULONG( PCI_IRQSEL_REGISTER, irqsel); // restore routage ECC
if (ErrAddr == READ_REGISTER_ULONG(PCI_ERRADDR_REGISTER)) {
Syndrome = READ_REGISTER_ULONG(PCI_SYNDROME_REGISTER);
ErrStatus = READ_REGISTER_ULONG(PCI_ERRSTATUS_REGISTER);
KeStallExecutionProcessor(100);
}
// We use SNI_PRIVATE_VECTOR to transmit parameters to the RM300 equivalent DCU' driver
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved=0;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis=FLAG_ECC_ERROR;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorSimmNum=HalpComputeNum((UCHAR *)ErrAddr);
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorAddress=ErrAddr;
// Call the 'RM300 equivalent DCU' driver to log the ECC error in event viewer
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
++HalpSingleEccCounter;
if (HalpSingleEccCounter > 0xffff) {
#if DBG
HalpSingleEccCounter = 0;
DebugPrint(("Memory Read Error Counter Overflow\n"));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 2;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "ECC SINGLE ERROR COUNTER OVERFLOW\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome);
#endif
}
} else {
#if DBG
// UNIX => PANIC
DebugPrint(("pci_ecc_error : errstatus=0x%x Add error=0x%x syndrome=0x%x \n",
ErrStatus,ErrAddr,Syndrome));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 3;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "UNCORRECTABLE ECC ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ErrAddr,HalpComputeNum((UCHAR *)ErrAddr),Syndrome);
#endif
}
}
}
if ( Itpend & PCI_ASIC_IOTIMEOUT ) {
ULONG ioadtimeout2, iomemconf;
ioadtimeout2 = READ_REGISTER_ULONG(PCI_IOADTIMEOUT2_REGISTER);
iomemconf = READ_REGISTER_ULONG(PCI_IOMEMCONF_REGISTER);
WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER ,
(iomemconf & (~PCI_IOMEMCONF_ENIOTMOUT)));
// reenable timeout
WRITE_REGISTER_ULONG( PCI_IOMEMCONF_REGISTER , iomemconf );
#if DBG
DebugPrint(("pci_timeout_error : adresse=0x%x \n",ioadtimeout2));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 4;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI TIMEOUT ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,ioadtimeout2,0,0);
#endif
}
}
//
// Pb NMI because of cirrus chip which generates a parity which is understood by the ASIC
// like an error and transmit as an NMI EISA.
//
if (MaStatus & PCI_MSR_NMI) {
UCHAR DataByte;
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus);
if (((PNMI_STATUS) &DataByte)->ParityNmi == 1) {
DebugPrint(("Parity error from system memory\n"));
// reset NMI interrupt
((PNMI_STATUS) &DataByte)->DisableEisaParity = 1;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte);
((PNMI_STATUS) &DataByte)->DisableEisaParity = 0;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte);
}
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl);
if (((PNMI_EXTENDED_CONTROL) &DataByte)->PendingBusMasterTimeout == 1) {
DebugPrint(("EISA Bus Master timeout\n"));
// reset NMI interrupt
((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 0;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte);
((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 1;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte);
}
}
//
// look for an PushButton Interrupt and simply dismiss it
//
if ( MaStatus & PCI_MSR_PB_MASK){
DebugPrint(("Interrupt - PushButton\n"));
WRITE_REGISTER_ULONG( PCI_CSRSTBP_ADDR ,0x0); // reset debug intr
#if DBG
DbgBreakPoint();
#endif
KeStallExecutionProcessor(500000); // sleep 0.5 sec
}
//
// look for an OverTemperature Interrupt and simply dismiss it
//
if ( MaStatus & PCI_MSR_TEMP_MASK){
DebugPrint(("Interrupt - Temperature\n"));
// we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to
// the 'RM300 equivalent DCU' driver
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //no ECC error
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
// if DCU driver not installed, Reset interrupt + auto-rearm
READ_REGISTER_ULONG( PCI_CLR_TMP_ADDR);
}
//
// look for an power off
//
if ( MaStatus & PCI_MSR_POFF_MASK){
// we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to
// the 'RM300 equivalent DCU' driver
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
// if DCU driver not installed, Reset interrupt + auto-rearm
WRITE_REGISTER_ULONG( PCI_CLRPOFF_ADDR,0);
}
//
// look for an power management
//
if ( MaStatus & PCI_MSR_PMGNT_MASK){
// we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to
// the 'RM300 equivalent DCU' driver
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= MaStatus;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
// if DCU driver not installed, Reset interrupt + auto-rearm
WRITE_REGISTER_ULONG( PCI_PWDN_ADDR,0); // power down
}
}
HalpCheckSpuriousInt(0x00);
return (TRUE); // perhaps one of the interrupts was pending :-)
}
BOOLEAN
HalpPciTowerInt0Dispatch (
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This routine handles the central INT0 Interrupt on an SNI PCI tower
To decide which interrupt, read the Interrupt Source Register
We have to manage priorities by software.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - Supplies a pointer to the Interrupt
Source register.
Return Value:
A BOOLEAN value, TRUE if the interrupt is OK,
otherwise FALSE for unknown interrupts
--*/
{
ULONG IntSource;
BOOLEAN SCSIresult, result;
if (HalpCheckSpuriousInt(0x400)) return(FALSE);
IntSource = READ_REGISTER_ULONG(ServiceContext);
if ( IntSource & PCI_TOWER_EISA_MASK) { // EISA Interrupt
if (HalpESC_SB)
result = HalpPciEisaSBDispatch( NULL, // InterruptObject (unused)
(PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
);
else
result = HalpPciEisaDispatch( NULL, // InterruptObject (unused)
(PVOID)EISA_CONTROL_PHYSICAL_BASE // ServiceContext
);
HalpCheckSpuriousInt(0x00);
return(result);
}
//
// look for SCSI Interrupts
//
if ( IntSource & PCI_TOWER_SCSI1_MASK){
SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI1_VECTOR])(
PCR->InterruptRoutine[SCSI1_VECTOR]
);
#if DBG
if(!SCSIresult) DebugPrint(("Got an invalid SCSI 1 interrupt !\n"));
#endif
HalpCheckSpuriousInt(0x00);
return(SCSIresult);
}
if ( IntSource & PCI_TOWER_SCSI2_MASK){
SCSIresult = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SCSI2_VECTOR])(
PCR->InterruptRoutine[SCSI2_VECTOR]
);
#if DBG
if(!SCSIresult) DebugPrint(("Got an invalid SCSI 2 interrupt !\n"));
#endif
HalpCheckSpuriousInt(0x00);
return(SCSIresult);
}
//
// PCI interrupts
//
if ( IntSource & PCI_TOWER_INTA_MASK){
int i;
for (i=INTA_VECTOR;i<HalpIntAMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_TOWER_INTB_MASK){
int i;
for (i=INTB_VECTOR;i<HalpIntBMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_TOWER_INTC_MASK){
int i;
for (i=INTC_VECTOR;i<HalpIntCMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
if ( IntSource & PCI_TOWER_INTD_MASK){
int i;
for (i=INTD_VECTOR;i<HalpIntDMax;++i)
((PSECONDARY_DISPATCH) PCR->InterruptRoutine[i])(
PCR->InterruptRoutine[i]
);
HalpCheckSpuriousInt(0x00);
return(TRUE);
}
HalpCheckSpuriousInt(0x00);
return (TRUE); // perhaps one of the interrupts was pending :-)
}
BOOLEAN
HalpPciTowerInt3Dispatch (
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This routine handles the MAUI-INT4 Interrupt on an SNI PCI tower :
- DCU interrupt (extra_timer,...)
- MPBus error
- Memory error
- PCI error
To decide which interrupt, read the Interrupt Source Register
We have to manage priorities by software.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - Supplies a pointer to the Interrupt
Source register.
Return Value:
A BOOLEAN value, TRUE if the interrupt is OK,
otherwise FALSE for unknown interrupts
--*/
{
ULONG IntSource;
ULONG mem_addr,status;
ULONG status0,status1;
BOOLEAN result;
if (HalpCheckSpuriousInt(0x2000)) return(FALSE);
IntSource = READ_REGISTER_ULONG(ServiceContext);
//
// look if a DCU_INDICATE interrupt occured
//
//
if (IntSource & PCI_TOWER_D_INDICATE_MASK){
status = READ_REGISTER_ULONG(PCI_TOWER_INDICATE);
//
// look if extra timer interrupt
//
if (status & PCI_TOWER_DI_EXTRA_TIMER){
HalpClockInterruptPciTower();
return(TRUE);
}
DebugPrint(("DCU_INDICATE interrupt\n"));
//
// look for an PushButton Interrupt and simply dismiss it
//
if ( status & PCI_TOWER_DI_PB_MASK){
DebugPrint(("Interrupt - PushButton\n"));
#if DBG
DbgBreakPoint();
#endif
KeStallExecutionProcessor(500000); // sleep 0.5 sec
return(TRUE);
}
//The reading of DCU_INDICATE register clears the interrupt sources
// --> we use SNI_PRIVATE_VECTOR->DCU_reserved to transmit the interrupt sources to
// the DCU driver
result = TRUE;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= status;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
// if DCU driver not installed, reset EISA_NMI interrupt if necessary
if (status & PCI_TOWER_DI_EISA_NMI)
{
UCHAR DataByte;
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus);
if (((PNMI_STATUS) &DataByte)->ParityNmi == 1)
{
DebugPrint(("Parity error from system memory\n"));
//reset NMI interrupt //
((PNMI_STATUS) &DataByte)->DisableEisaParity = 1;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte);
((PNMI_STATUS) &DataByte)->DisableEisaParity = 0;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->NmiStatus,DataByte);
}
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl);
if (((PNMI_EXTENDED_CONTROL) &DataByte)->PendingBusMasterTimeout == 1)
{
DebugPrint(("EISA Bus Master timeout\n"));
//reset NMI interrupt //
((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 0;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte);
((PNMI_EXTENDED_CONTROL) &DataByte)->EnableBusMasterTimeout = 1;
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpOnboardControlBase)->ExtendedNmiResetControl,DataByte);
}
}
return (result);
}
//
// look if a DCU_ERROR interrupt occured
//
//
if (IntSource & PCI_TOWER_D_ERROR_MASK){
status = 0;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved= 0;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis = 0; //No ECC error
result =(((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
// read DCU_ERROR register to clear interrupt source if DCU driver not installed
READ_REGISTER_ULONG(PCI_TOWER_DCU_ERROR);
return (result);
}
//
// look if MP_BUS error
//
if (IntSource & PCI_TOWER_MP_BUS_MASK){
status = READ_REGISTER_ULONG(PCI_TOWER_MP_BUS_ERROR_STATUS);
mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MP_BUS_ERROR_ADDR);
// Clear MP_Bus interrupt
WRITE_REGISTER_ULONG (ServiceContext,IntSource);
if (IntSource & PCI_TOWER_C_PARITY_MASK){
#if DBG
DebugPrint(("MP_Bus Parity Error : MPBusErrorStatus = 0x%x MPBusErrorAddress = 0x%x \n",
status,mem_addr));
//DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 5;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MP_BUS PARITY ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0);
#endif
}
if (IntSource & PCI_TOWER_C_REGSIZE){
#if DBG
DebugPrint(("MP_Bus Register Size Error : MPBusErrorStatus = 0x%x \n",
status));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 6;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MP_BUS REGISTER SIZE ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,0,0);
#endif
}
}
//
// look if Memory error
//
if (IntSource & PCI_TOWER_M_ECC_MASK){
mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR)& MEM_ADDR_MASK;
// correct ECC error
HalpMultiPciEccCorrector(mem_addr ,mem_addr >> PAGE_SHIFT,4);
IntSource = READ_REGISTER_ULONG(PCI_TOWER_GEN_INTERRUPT);
if (IntSource & PCI_TOWER_M_ECC_MASK){
mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR)& MEM_ADDR_MASK;
KeStallExecutionProcessor(100);
}
// We use SNI_PRIVATE_VECTOR to transmit parameters to DCU driver
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved=0;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->DCU_reserved_bis=FLAG_ECC_ERROR;
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorSimmNum=HalpComputeNum((UCHAR *)mem_addr);
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->EccErrorAddress= mem_addr ;
// Call the 'DCU' driver to log the ECC error in event viewer
result = (((PSECONDARY_DISPATCH) PCR->InterruptRoutine[DCU_VECTOR])(
PCR->InterruptRoutine[DCU_VECTOR]
));
}
if (IntSource & PCI_TOWER_M_ADDR_MASK){
mem_addr = READ_REGISTER_ULONG(PCI_TOWER_MEM_ERROR_ADDR);
#if DBG
DebugPrint(("Memory Address Error : MemErrorAddr = 0x%x \n",mem_addr));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 7;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY ADDRESS ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,mem_addr,0,0);
#endif
}
if (IntSource & PCI_TOWER_M_SLT_MASK){
ULONG MemControl2,MemConf;
MemControl2 = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_2);
MemConf = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONFIG);
#if DBG
DebugPrint(("Memory slot Error : MemControl2 = 0x%x, MemConf = 0x%x \n",MemControl2,MemConf));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 8;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY SLOT ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,MemControl2,MemConf,0);
#endif
}
if (IntSource & PCI_TOWER_M_CFG_MASK){
ULONG MemControl2,MemConf;
MemControl2 = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_2);
MemConf = READ_REGISTER_ULONG(PCI_TOWER_MEM_CONFIG);
#if DBG
DebugPrint(("Memory Config Error : MemControl2 = 0x%x, MemConf = 0x%x \n",MemControl2,MemConf));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 9;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MEMORY CONFIG ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,MemControl2,MemConf,0);
#endif
}
if (IntSource & PCI_TOWER_M_RC_MASK){
// reset error counter
WRITE_REGISTER_ULONG (PCI_TOWER_MEM_CONTROL_1, (READ_REGISTER_ULONG(PCI_TOWER_MEM_CONTROL_1) & ERROR_COUNTER_MASK) | ERROR_COUNTER_INITVALUE);
#if DBG
DebugPrint(("Memory Read Error Counter Overflow\n"));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 2;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "ECC SINGLE ERROR COUNTER OVERFLOW\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,0,0,0);
#endif
}
//
// look if PCI interrupt
//
if (IntSource & PCI_TOWER_P_ERROR_MASK){
ULONG PciDataInt,PciData;
DebugPrint(("PCI interrupt \n"));
PciDataInt = PCI_TOWER_INTERRUPT_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
status = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
// First Initiator interrupt
if (status & PI_INITF){
PciData = PCI_TOWER_INITIATOR_ADDR_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
// Reset interrupt with write-1-to-clear bit Initiator_Interrupts
status0 = PI_INITF;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
if (status & PI_REC_TARGET_RETRY)
HalpTargetRetryCnt++;
else {
#if DBG
DebugPrint(("PCI Iniatiator interrupt error : Addr = 0x%x , PCI_interrupt register = 0x%x\n",
mem_addr,status));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 10;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI INITIATOR INTERRUPT ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0);
#endif
}
}
// First Target interrupt
if (status & PI_TARGF){
PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
// Reset interrupt with write-1-to-clear bit Target_Interrupts
status0 = PI_TARGF;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
#if DBG
DebugPrint(("PCI Target interrupt error : Addr = 0x%x , PCI_interrupt register = 0x%x\n",
mem_addr,status));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 11;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI TARGET INTERRUPT ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0);
#endif
}
// First parity error
if (status & PI_PARF){
// Reset interrupt with write-1-to-clear bit Parity_Interrupts
status0 = PI_PARF;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
PciData = PCI_TOWER_PAR_0_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
status0 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
PciData = PCI_TOWER_PAR_1_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
status1 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
#if DBG
DebugPrint(("PCI Parity interrupt error : Parity_0 register = 0x%x , Parity_1 register = 0x%x\n",
status0,status1));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 12;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "PCI PARITY INTERRUPT ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status0,status1,0);
#endif
}
// Multiple Initiator interrupts
if (status & PI_INITM){
PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
// Reset interrupt with write-1-to-clear bit Multiple Initiator_Interrupts
status0 = PI_INITM;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
if (!(status & PI_REC_TARGET_RETRY)) {
#if DBG
DebugPrint(("Multiple PCI Iniatiator interrupt : Addr = 0x%x , PCI_interrupt register = 0x%x\n",
mem_addr,status));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 13;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI INITIATOR ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0);
#endif
}
}
// Multiple Target interrupts
if (status & PI_TARGM){
PciData = PCI_TOWER_TARGET_ADDR_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
mem_addr = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
// Reset interrupt with write-1-to-clear bit Multiple Target_interrupts
status0 = PI_TARGM;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
#if DBG
DebugPrint(("Multiple PCI Target interrupt : Addr = 0x%x , PCI_interrupt register = 0x%x\n",
mem_addr,status));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 14;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI TARGET ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status,mem_addr,0);
#endif
}
// Multiple Parity interrupts
if (status & PI_PARM){
// Reset interrupt with write-1-to-clear bit Multiple Parity_Interrupts
status0 = PI_PARM;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status0));
PciData = PCI_TOWER_PAR_0_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
status0 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
PciData = PCI_TOWER_PAR_1_OFFSET | 0x80000000;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciData));
status1 = READ_REGISTER_ULONG ((PULONG) HalpPciConfigData);
#if DBG
DebugPrint(("Multiple PCI Parity interrupt : Parity_0 register = 0x%x , Parity_1 register = 0x%x\n",
status0,status1));
DbgBreakPoint();
#else
HalpDisableInterrupts(); // for the MATROX boards...
HalpColumn = 0;HalpRow = 0; // if we already were in VGA mode
HalDisplayString("\n");
HalpClearVGADisplay();
HalpBugCheckNumber = 15;
HalDisplayString(HalpBugCheckMessage[HalpBugCheckNumber]); // "MULTIPLE PCI PARITY ERROR\n"
HalpKeBugCheckEx(NMI_HARDWARE_FAILURE,HalpBugCheckNumber,status0,status1,0);
#endif
}
//reenable PCI interrupt
status &= MASK_INT;
WRITE_REGISTER_ULONG(HalpPciConfigAddr, *((PULONG) &PciDataInt));
WRITE_REGISTER_ULONG ((PULONG) HalpPciConfigData, *((PULONG) &status));
}
HalpCheckSpuriousInt(0x00);
return (TRUE); // perhaps one of the interrupts was pending :-)
}