1076 lines
26 KiB
C
1076 lines
26 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
Copyright (c) 1992, 1993 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
mkintsup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The module provides the interrupt support for Mikasa EV5 (Pinnacle) systems.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Eric Rehm (DEC) 29-December-1993
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Scott Lee (DEC) 30-Nov-1995
|
|||
|
Adapted from Mikasa module for Mikasa EV5 (Pinnacle).
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "eisa.h"
|
|||
|
#include "ebsgdma.h"
|
|||
|
#include "mikasa.h"
|
|||
|
#include "pcrtc.h"
|
|||
|
#include "pintolin.h"
|
|||
|
|
|||
|
//
|
|||
|
// Import globals declared in HalpMapIoSpace.
|
|||
|
//
|
|||
|
|
|||
|
extern PVOID HalpServerControlQva;
|
|||
|
|
|||
|
extern PVOID HalpMikasaPciIrQva;
|
|||
|
extern PVOID HalpMikasaPciImrQva;
|
|||
|
|
|||
|
extern PVOID HalpNoritakePciIr1Qva;
|
|||
|
extern PVOID HalpNoritakePciIr2Qva;
|
|||
|
extern PVOID HalpNoritakePciIr3Qva;
|
|||
|
extern PVOID HalpNoritakePciImr1Qva;
|
|||
|
extern PVOID HalpNoritakePciImr2Qva;
|
|||
|
extern PVOID HalpNoritakePciImr3Qva;
|
|||
|
|
|||
|
extern PVOID HalpCorellePciIr1Qva;
|
|||
|
extern PVOID HalpCorellePciIr2Qva;
|
|||
|
extern PVOID HalpCorellePciImr1Qva;
|
|||
|
extern PVOID HalpCorellePciImr2Qva;
|
|||
|
|
|||
|
//
|
|||
|
// Import global from PCI interrupt management functions.
|
|||
|
//
|
|||
|
extern USHORT HalpMikasaPciInterruptMask;
|
|||
|
|
|||
|
extern USHORT HalpNoritakePciInterrupt1Mask;
|
|||
|
extern USHORT HalpNoritakePciInterrupt2Mask;
|
|||
|
extern USHORT HalpNoritakePciInterrupt3Mask;
|
|||
|
|
|||
|
extern USHORT HalpCorellePciInterrupt1Mask;
|
|||
|
extern USHORT HalpCorellePciInterrupt2Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Define reference to platform identifier
|
|||
|
//
|
|||
|
|
|||
|
extern BOOLEAN HalpNoritakePlatform;
|
|||
|
extern BOOLEAN HalpCorellePlatform;
|
|||
|
|
|||
|
//
|
|||
|
// Declare the interrupt structures and spinlocks for the intermediate
|
|||
|
// interrupt dispatchers.
|
|||
|
//
|
|||
|
|
|||
|
KINTERRUPT HalpPciInterrupt;
|
|||
|
KINTERRUPT HalpEisaInterrupt;
|
|||
|
|
|||
|
//
|
|||
|
// Declare the interrupt dispatch routine for PCI/EISA interrupts. The
|
|||
|
// interrupt dispatch routine, HalpPciDispatch or HalpEisaDispatch, is called
|
|||
|
// from this handler.
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpDeviceDispatch(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpPciDispatch(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The following is the interrupt object used for DMA controller interrupts.
|
|||
|
// DMA controller interrupts occur when a memory parity error occurs or a
|
|||
|
// programming error occurs to the DMA controller.
|
|||
|
//
|
|||
|
|
|||
|
KINTERRUPT HalpEisaNmiInterrupt;
|
|||
|
|
|||
|
UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n";
|
|||
|
ULONG NMIcount = 0;
|
|||
|
|
|||
|
//
|
|||
|
// The following function initializes NMI handling.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeNMI(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The following function is called when an EISA NMI occurs.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalHandleNMI(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// PCI initialization routines
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeMikasaPciInterrupts(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeNoritakePciInterrupts(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeCorellePciInterrupts(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpInitializeMikasaAndNoritakeInterrupts(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the structures necessary for EISA & PCI operations
|
|||
|
and connects the intermediate interrupt dispatchers. It also initializes
|
|||
|
the EISA interrupt controller; the Mikasa, Noritake, and Corelle ESC
|
|||
|
interrupt controllers are compatible with the EISA interrupt controller
|
|||
|
used on Jensen.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the second level interrupt dispatchers are connected, then a value of
|
|||
|
TRUE is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KIRQL oldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the EISA NMI interrupt.
|
|||
|
//
|
|||
|
|
|||
|
HalpInitializeNMI();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Intitialize interrupt controller
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(DEVICE_HIGH_LEVEL, &oldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// There's no initialization required for the Mikasa PCI interrupt
|
|||
|
// "controller," as it's the wiring of the hardware, rather than a
|
|||
|
// PIC like the 82c59 that directs interrupts. We do set the IMR to
|
|||
|
// zero to disable all interrupts, initially.
|
|||
|
//
|
|||
|
// The Noritake requires a separate routine to setup the 3 interrupt
|
|||
|
// mask registers correctly.
|
|||
|
//
|
|||
|
// Corelle requires a separate routine to setup the 2 interrupt mask
|
|||
|
// registers correctly.
|
|||
|
//
|
|||
|
|
|||
|
if( HalpNoritakePlatform ) {
|
|||
|
|
|||
|
HalpInitializeNoritakePciInterrupts();
|
|||
|
|
|||
|
} else if ( HalpCorellePlatform ) {
|
|||
|
|
|||
|
HalpInitializeCorellePciInterrupts();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HalpInitializeMikasaPciInterrupts();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We must initialize the ESC's PICs, for EISA interrupts.
|
|||
|
//
|
|||
|
|
|||
|
HalpInitializeEisaInterrupts();
|
|||
|
|
|||
|
//
|
|||
|
// Restore the IRQL.
|
|||
|
//
|
|||
|
|
|||
|
KeLowerIrql(oldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the EISA DMA mode registers to a default value.
|
|||
|
// Disable all of the DMA channels except channel 4 which is the
|
|||
|
// cascade of channels 0-3.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
|
|||
|
0x0F
|
|||
|
);
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
|
|||
|
0x0E
|
|||
|
);
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpDeviceDispatch(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is entered as a result of an interrupt being generated via
|
|||
|
the vector that is connected to an interrupt object associated with the
|
|||
|
PCI/EISA device interrupts. Its function is to call the second-level
|
|||
|
interrupt dispatch routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interrupt - Supplies a pointer to the interrupt object.
|
|||
|
|
|||
|
ServiceContext - Supplies a pointer to the PCI interrupt register.
|
|||
|
|
|||
|
TrapFrame - Supplies a pointer to the trap frame for this interrupt.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the value returned from the second level routine.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
USHORT IrContents;
|
|||
|
BOOLEAN returnValue;
|
|||
|
|
|||
|
//
|
|||
|
// Read the PCI interrupt register.
|
|||
|
//
|
|||
|
|
|||
|
if (HalpNoritakePlatform) {
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpNoritakePciIr1Qva));
|
|||
|
IrContents &= HalpNoritakePciInterrupt1Mask;
|
|||
|
|
|||
|
} else if ( HalpCorellePlatform ) {
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpCorellePciIr1Qva));
|
|||
|
IrContents &= HalpCorellePciInterrupt1Mask;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpMikasaPciIrQva));
|
|||
|
IrContents &= HalpMikasaPciInterruptMask;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine whether a PCI interrupt or an EISA interrupt occurred
|
|||
|
//
|
|||
|
|
|||
|
if (IrContents) {
|
|||
|
|
|||
|
//
|
|||
|
// PCI interrupt. Call HalpPciDispatch.
|
|||
|
//
|
|||
|
|
|||
|
if (HalpNoritakePlatform) {
|
|||
|
|
|||
|
returnValue = HalpPciDispatch(Interrupt, HalpNoritakePciIr1Qva,
|
|||
|
TrapFrame);
|
|||
|
|
|||
|
} else if ( HalpCorellePlatform ) {
|
|||
|
|
|||
|
returnValue = HalpPciDispatch(Interrupt, HalpCorellePciIr1Qva,
|
|||
|
TrapFrame);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
returnValue = HalpPciDispatch(Interrupt, HalpMikasaPciIrQva,
|
|||
|
TrapFrame);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// EISA interrupt. Call HalpEisaDispatch.
|
|||
|
//
|
|||
|
|
|||
|
returnValue = HalpEisaDispatch(Interrupt, HalpEisaIntAckBase,
|
|||
|
TrapFrame);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return returnValue;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpNmiInterrupt (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the NMI interrupts that are routed to pwr_fail_irq_h.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Call HalHandleNMI to handle the interrupt
|
|||
|
//
|
|||
|
|
|||
|
HalHandleNMI(NULL, NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeNMI(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called to initialize ESC NMI interrupts.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR DataByte;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the ESC NMI interrupt.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeInterrupt( &HalpEisaNmiInterrupt,
|
|||
|
HalHandleNMI,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
EISA_NMI_VECTOR,
|
|||
|
EISA_NMI_LEVEL,
|
|||
|
EISA_NMI_LEVEL,
|
|||
|
LevelSensitive,
|
|||
|
FALSE,
|
|||
|
0,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Don't fail if the interrupt cannot be connected.
|
|||
|
//
|
|||
|
|
|||
|
KeConnectInterrupt( &HalpEisaNmiInterrupt );
|
|||
|
|
|||
|
//
|
|||
|
// Clear the Eisa NMI disable bit. This bit is the high order of the
|
|||
|
// NMI enable register. Note that the other bits should be left as
|
|||
|
// they are, according to the chip's documentation.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable);
|
|||
|
((PNMI_ENABLE)(&DataByte))->NmiDisable = 0;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, DataByte);
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalpIntializeNMI: wrote 0x%x to NmiEnable\n\r", DataByte);
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// jwlfix - I'll have to make this do something useful, since the console
|
|||
|
// halt button on Mikasa is connected to this interrupt. To start,
|
|||
|
// it will be a useful way to see if the interrupt gets connected.
|
|||
|
// The simple path is to check the server management register to
|
|||
|
// see if the "halt" button has been pressed on the operator's
|
|||
|
// console, and then initiate a hardware reset. On the other hand,
|
|||
|
// a server might not want to be halted so readily as that.
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalHandleNMI(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called when an EISA NMI occurs. It prints the
|
|||
|
appropriate status information and bugchecks.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interrupt - Supplies a pointer to the interrupt object
|
|||
|
|
|||
|
ServiceContext - Bug number to call bugcheck with.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR StatusByte;
|
|||
|
UCHAR EisaPort;
|
|||
|
ULONG port;
|
|||
|
ULONG AddressSpace = 1; // 1 = I/O address space
|
|||
|
BOOLEAN Status;
|
|||
|
PHYSICAL_ADDRESS BusAddress;
|
|||
|
PHYSICAL_ADDRESS TranslatedAddress;
|
|||
|
UCHAR Datum;
|
|||
|
ULONG Ir1Contents, Ir3Contents;
|
|||
|
|
|||
|
NMIcount++;
|
|||
|
|
|||
|
//
|
|||
|
// Set the Eisa NMI disable bit. We do this to mask further NMI
|
|||
|
// interrupts while we're servicing this one.
|
|||
|
//
|
|||
|
Datum = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable);
|
|||
|
((PNMI_ENABLE)(&Datum))->NmiDisable = 1;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, Datum);
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalpIntializeNMI: wrote 0x%x to NmiEnable\n\r", Datum);
|
|||
|
#endif
|
|||
|
|
|||
|
StatusByte =
|
|||
|
READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
|
|||
|
|
|||
|
if (StatusByte & 0x80) {
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Parity Check / Parity Error\n");
|
|||
|
DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte);
|
|||
|
#else
|
|||
|
//
|
|||
|
// jwlfix - For the present, we're commenting out an NMI parity
|
|||
|
// error bugcheck, until investigation into its causes
|
|||
|
// yields a better solution.
|
|||
|
//
|
|||
|
// HalDisplayString ("NMI: Parity Check / Parity Error\n");
|
|||
|
// KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
// return (TRUE);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Handle the server management interrupts.
|
|||
|
// sclfix - We will dismiss these interrupts for now. This will need to be
|
|||
|
// change once we decide how to handle server management features.
|
|||
|
//
|
|||
|
|
|||
|
Datum = READ_PORT_UCHAR((PUCHAR)HalpServerControlQva );
|
|||
|
|
|||
|
if (HalpNoritakePlatform) {
|
|||
|
|
|||
|
Ir3Contents = (ULONG)(READ_PORT_USHORT((PUSHORT)HalpNoritakePciIr3Qva));
|
|||
|
|
|||
|
if (((PNORITAKE_SRV)(&Datum))->HaltIncoming == 0 ||
|
|||
|
((PNORITAKE_IMR3)(&Status))->TempWarn == 0 ||
|
|||
|
((PNORITAKE_IMR3)(&Status))->Power2Int == 0 ||
|
|||
|
((PNORITAKE_IMR3)(&Status))->Power1Int == 0 ||
|
|||
|
((PNORITAKE_IMR3)(&Status))->Fan2Fail == 0 ||
|
|||
|
((PNORITAKE_IMR3)(&Status))->Fan1Fail == 0) {
|
|||
|
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Server management NMI\n");
|
|||
|
DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte);
|
|||
|
DbgPrint("HalHandleNMI: Server management byte = 0x%x\r\n", Datum);
|
|||
|
DbgPrint("HalHandleNMI: Ir3 contents = 0x%x\r\n", Ir3Contents);
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else if (HalpCorellePlatform) {
|
|||
|
|
|||
|
Ir1Contents = (ULONG)(READ_PORT_USHORT((PUSHORT)HalpCorellePciIr1Qva));
|
|||
|
|
|||
|
if (((PCORELLE_SRV)(&Datum))->HaltIncoming == 0 ||
|
|||
|
((PCORELLE_IMR1)(&Status))->TempFailInt == 0 ||
|
|||
|
((PCORELLE_IMR1)(&Status))->TempWarnInt == 0 ||
|
|||
|
((PCORELLE_IMR1)(&Status))->Fan1FailInt == 0 ||
|
|||
|
((PCORELLE_IMR1)(&Status))->Fan2FailInt == 0) {
|
|||
|
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Server management NMI\n");
|
|||
|
DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte);
|
|||
|
DbgPrint("HalHandleNMI: Server managemnt byte = 0x%x\r\n", Datum);
|
|||
|
DbgPrint("HalHandleNMI: Ir1 contents = 0x%x\r\n", Ir1Contents);
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (((PMIKASA_SRV)(&Datum))->HaltIncoming == 0 ||
|
|||
|
((PMIKASA_SRV)(&Datum))->TempFail == 1 ||
|
|||
|
((PMIKASA_SRV)(&Datum))->DcOk1 == 0 ||
|
|||
|
((PMIKASA_SRV)(&Datum))->DcOk2 == 0 ||
|
|||
|
((PMIKASA_SRV)(&Datum))->Fan1Fault == 0 ||
|
|||
|
((PMIKASA_SRV)(&Datum))->Fan2Fault == 0) {
|
|||
|
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Server management NMI\n");
|
|||
|
DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte);
|
|||
|
DbgPrint("HalHandleNMI: Server Management Byte = 0x%x\r\n", Datum);
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (StatusByte & 0x40) {
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Channel Check / IOCHK\n");
|
|||
|
DbgPrint("HalHandleNMI: StatusByte = 0x%x\r\n", StatusByte);
|
|||
|
#else
|
|||
|
HalDisplayString ("NMI: Channel Check / IOCHK\n");
|
|||
|
KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
return (TRUE);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
// jwlfix - This code can be added in later, as we have need
|
|||
|
// for it. It's good to have it here, for when it
|
|||
|
// might be of use.
|
|||
|
//
|
|||
|
// This is an Eisa machine, check for extnded nmi information...
|
|||
|
//
|
|||
|
|
|||
|
StatusByte = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl);
|
|||
|
|
|||
|
if (StatusByte & 0x80) {
|
|||
|
HalDisplayString ("NMI: Fail-safe timer\n");
|
|||
|
}
|
|||
|
|
|||
|
if (StatusByte & 0x40) {
|
|||
|
HalDisplayString ("NMI: Bus Timeout\n");
|
|||
|
}
|
|||
|
|
|||
|
if (StatusByte & 0x20) {
|
|||
|
HalDisplayString ("NMI: Software NMI generated\n");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Look for any Eisa expansion board. See if it asserted NMI.
|
|||
|
//
|
|||
|
// jwlfix - The following doesn't work, at this moment; it's
|
|||
|
// likey the 12-bit shift, which should be a 5-bit
|
|||
|
// shift on Mikasa.
|
|||
|
//
|
|||
|
|
|||
|
BusAddress.HighPart = 0;
|
|||
|
|
|||
|
for (EisaPort = 0; EisaPort <= 0xf; EisaPort++)
|
|||
|
{
|
|||
|
BusAddress.LowPart = (EisaPort << 12) + 0xC80;
|
|||
|
|
|||
|
Status = HalTranslateBusAddress(Eisa, // InterfaceType
|
|||
|
0, // BusNumber
|
|||
|
BusAddress,
|
|||
|
&AddressSpace, // 1=I/O address space
|
|||
|
&TranslatedAddress); // QVA
|
|||
|
if (Status == FALSE)
|
|||
|
{
|
|||
|
UCHAR pbuf[80];
|
|||
|
sprintf(pbuf,
|
|||
|
"Unable to translate bus address %x for EISA slot %d\n",
|
|||
|
BusAddress.LowPart, EisaPort);
|
|||
|
HalDisplayString(pbuf);
|
|||
|
KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
port = TranslatedAddress.LowPart;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
|
|||
|
StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
|
|||
|
|
|||
|
if ((StatusByte & 0x80) == 0) {
|
|||
|
//
|
|||
|
// Found valid Eisa board, Check to see if its
|
|||
|
// IOCHKERR is asserted.
|
|||
|
//
|
|||
|
|
|||
|
StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
|
|||
|
if (StatusByte & 0x2) {
|
|||
|
EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
|
|||
|
HalDisplayString (EisaNMIMsg);
|
|||
|
KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#ifdef HALDBG
|
|||
|
// Reset extended NMI interrupts (for debugging purposes only).
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02);
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalHandleNMI: Resetting PERR#; NMI count = %d\r\n", NMIcount);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Reset PERR# and disable it.
|
|||
|
//
|
|||
|
WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0x04);
|
|||
|
|
|||
|
//
|
|||
|
// now enable it again.
|
|||
|
//
|
|||
|
WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, 0);
|
|||
|
|
|||
|
//
|
|||
|
// Clear the Eisa NMI disable bit. This re-enables NMI interrupts,
|
|||
|
// now that we're done servicing this one.
|
|||
|
//
|
|||
|
Datum = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable);
|
|||
|
((PNMI_ENABLE)(&Datum))->NmiDisable = 0;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable, Datum);
|
|||
|
#ifdef HALDBG
|
|||
|
DbgPrint("HalpIntializeNMI: wrote 0x%x to NmiEnable\n\r", Datum);
|
|||
|
#endif
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
UCHAR
|
|||
|
HalpAcknowledgeEisaInterrupt(
|
|||
|
PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Acknowledge the EISA interrupt from the programmable interrupt controller.
|
|||
|
Return the vector number of the highest priority pending interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceContext - Service context of the interrupt service supplies
|
|||
|
a pointer to the EISA interrupt acknowledge register.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return the value of the highest priority pending interrupt.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR InterruptVector;
|
|||
|
|
|||
|
//
|
|||
|
// Read the interrupt vector from the PIC.
|
|||
|
//
|
|||
|
|
|||
|
InterruptVector = (UCHAR) (INTERRUPT_ACKNOWLEDGE(ServiceContext));
|
|||
|
|
|||
|
return( InterruptVector );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR
|
|||
|
HalpAcknowledgeMikasaPciInterrupt(
|
|||
|
PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Acknowledge the PCI interrupt. Return the vector number of the
|
|||
|
highest priority pending interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceContext - Service context of the interrupt service supplies
|
|||
|
a pointer to the Mikasa PCI interrupt register QVA.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return the value of the highest priority pending interrupt.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR InterruptVector = 0;
|
|||
|
USHORT IrContents;
|
|||
|
int i;
|
|||
|
|
|||
|
//
|
|||
|
// Find the first zero bit in the register, starting from the highest
|
|||
|
// order bit. This implies a priority ordering that makes a certain
|
|||
|
// amount of sense, in that bits 14 and 13 indicate temperature and
|
|||
|
// power faults, while bit 12 is the Ncr53c810. Note that it's
|
|||
|
// necessary to add one to the bit number to make the interrupt
|
|||
|
// vector, a unit-origin value in the pin-to-line table. We do
|
|||
|
// this by starting i at 16 and ending it at 1; that means zero
|
|||
|
// is a non-enabled interrupt indication.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First, get and complement the interrupt register, so that the
|
|||
|
// pending interrupts will be the "1" bits. Then mask with the
|
|||
|
// enabled mask, HalpMikasaPciInterruptMask;
|
|||
|
//
|
|||
|
|
|||
|
IrContents = ~(0xffff & READ_PORT_USHORT( (PUSHORT)ServiceContext ));
|
|||
|
IrContents &= HalpMikasaPciInterruptMask;
|
|||
|
|
|||
|
for (i = 16; i >= 1; i-- ) {
|
|||
|
if ( IrContents & 0x8000 ) {
|
|||
|
InterruptVector = i;
|
|||
|
break;
|
|||
|
} else {
|
|||
|
IrContents <<= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return( InterruptVector );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR
|
|||
|
HalpAcknowledgeNoritakePciInterrupt(
|
|||
|
PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Acknowledge the PCI interrupt. Return the vector number of the
|
|||
|
highest priority pending interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceContext - Service context of the interrupt service supplies
|
|||
|
a pointer to the Noritake PCI interrupt register 1 QVA.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return the value of the highest priority pending interrupt.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR InterruptVector = 0;
|
|||
|
USHORT IrContents;
|
|||
|
int i;
|
|||
|
|
|||
|
//
|
|||
|
// Interrupt1 register contains the sum of all interrupts of Interrupt2
|
|||
|
// and Interrupt3 registers in bit 0. The rest of the register contains
|
|||
|
// the A and B interrupts of the 7 PCI slots. Interrupt2 register
|
|||
|
// contains the sum of all of the unmasked interrupts of Interrupt 2 in bit
|
|||
|
// 0. Bit 1 is asserted when any secondary PCI bus interrupt is asserted
|
|||
|
// (including those in interrupt register 1) and the posted write buffers
|
|||
|
// in the PPB have been flushed. The rest of the register contians the C
|
|||
|
// and D interrupts of all of the slots. Interrupt3 register contains some
|
|||
|
// safety and reliability interrupts. Please see mikasa.h for the
|
|||
|
// definitions of which interrupt is at which bit in the register.
|
|||
|
//
|
|||
|
// Each bit in the registers corresponds to an interrupt vector (which
|
|||
|
// will later have PCI_VECTORS added to it.) This vector can be obtained
|
|||
|
// by adding the vector offset for that register to the bit position.
|
|||
|
// These offsets are also defined in mikasa.h.
|
|||
|
//
|
|||
|
// All registers are "reverse-logic" (active low), where a 0 means that an
|
|||
|
// interrupt is waiting. That is why we must complement the contents of
|
|||
|
// the register before we mask with HalpNoritakePciInterruptXMask.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First, get and complement the first interrupt register, so that the
|
|||
|
// pending interrupts will be the "1" bits. Then mask with the
|
|||
|
// enabled mask, HalpNoritakePciInterrupt1Mask;
|
|||
|
//
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpNoritakePciIr1Qva));
|
|||
|
IrContents &= HalpNoritakePciInterrupt1Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Position bit 1 as the lowest bit. We will start checking here - this
|
|||
|
// is the first "real" interrupt.
|
|||
|
//
|
|||
|
|
|||
|
IrContents >>= 1;
|
|||
|
|
|||
|
for( i = 1; i < 16; i++ ) {
|
|||
|
if( IrContents & 0x1 ) {
|
|||
|
InterruptVector = i + REGISTER_1_VECTOR_OFFSET;
|
|||
|
break;
|
|||
|
}
|
|||
|
IrContents >>= 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if( InterruptVector == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// We didn't find any interrupts in interrupt register 1.
|
|||
|
// Check interrupt register 2.
|
|||
|
//
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpNoritakePciIr2Qva));
|
|||
|
IrContents &= HalpNoritakePciInterrupt2Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Position bit 2 in the lowest bit. We will start checking here -
|
|||
|
// this is the first "real" interrupt.
|
|||
|
//
|
|||
|
|
|||
|
IrContents >>= 2;
|
|||
|
|
|||
|
for( i = 2; i < 16; i++ ) {
|
|||
|
if( IrContents & 0x1 ) {
|
|||
|
InterruptVector = i + REGISTER_2_VECTOR_OFFSET;
|
|||
|
break;
|
|||
|
}
|
|||
|
IrContents >>= 1;
|
|||
|
}
|
|||
|
|
|||
|
if( InterruptVector == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// We didn't find any interrupts in interrupt register 2.
|
|||
|
// Check Interrupt Register 3.
|
|||
|
//
|
|||
|
|
|||
|
IrContents = ~(0xffff &
|
|||
|
READ_PORT_USHORT((PUSHORT)HalpNoritakePciIr3Qva));
|
|||
|
IrContents &= HalpNoritakePciInterrupt3Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Position bit 2 in the lowest bit. We will start checking here -
|
|||
|
// this is the first "real" interrupt.
|
|||
|
//
|
|||
|
|
|||
|
IrContents >>= 2;
|
|||
|
|
|||
|
for( i = 2; i < 6; i++ ) {
|
|||
|
if( IrContents & 0x1 ) {
|
|||
|
InterruptVector = i + REGISTER_3_VECTOR_OFFSET;
|
|||
|
break;
|
|||
|
}
|
|||
|
IrContents >>= 1;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( InterruptVector );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR
|
|||
|
HalpAcknowledgeCorellePciInterrupt(
|
|||
|
PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Acknowledge the PCI interrupt. Return the vector number of the
|
|||
|
highest priority pending interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceContext - Service context of the interrupt service supplies
|
|||
|
a pointer to the Noritake PCI interrupt register 1 QVA.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return the value of the highest priority pending interrupt.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
UCHAR InterruptVector = 0;
|
|||
|
USHORT IrContents;
|
|||
|
int i;
|
|||
|
|
|||
|
//
|
|||
|
// Interrupt register 1 contains the INTA and INTB interrupts. Bit 0 of
|
|||
|
// the interrupt register contains the sum of all interrupts in interrupt
|
|||
|
// register 2 which contains the INTC and INTD interrupts. The interrupts
|
|||
|
// for the onboard SCSI (QLOGIC) and video (S3 TRIO 64) are also contained
|
|||
|
// in interrupt register 1. All the signals in the interrupt registers are
|
|||
|
// active low.
|
|||
|
|
|||
|
//
|
|||
|
// First, get and complement the first interrupt register, so that the
|
|||
|
// pending interrupts will be the "1" bits. Then mask with the
|
|||
|
// enabled mask, HalpCorellePciInterrupt1Mask;
|
|||
|
//
|
|||
|
|
|||
|
IrContents =
|
|||
|
~(0xffff & READ_PORT_USHORT((PUSHORT)HalpCorellePciIr1Qva));
|
|||
|
IrContents &= HalpCorellePciInterrupt1Mask;
|
|||
|
|
|||
|
//
|
|||
|
// We will check for interrupts by starting from bit 1 of interrupt
|
|||
|
// register 1. We will stop at bit 10 since bit 11 is reserved and always
|
|||
|
// 1 and bit 12 to 15 are server management related interrupts.
|
|||
|
//
|
|||
|
|
|||
|
IrContents >>= 1;
|
|||
|
|
|||
|
for (i = 1; i < 11; i++) {
|
|||
|
|
|||
|
if (IrContents & 0x1) {
|
|||
|
|
|||
|
InterruptVector = i + CORELLE_INTERRUPT1_OFFSET;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IrContents >>= 1;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (InterruptVector == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Did not find any interrupts in interrupt register 1. Check interrupt
|
|||
|
// register 2.
|
|||
|
//
|
|||
|
|
|||
|
IrContents = ~(0xffff & READ_PORT_USHORT((PUSHORT)HalpCorellePciIr2Qva));
|
|||
|
IrContents &= HalpCorellePciInterrupt2Mask;
|
|||
|
|
|||
|
//
|
|||
|
// We will start at bit 2 and stop at bit 9. The other bits are reserved
|
|||
|
// and always 1.
|
|||
|
//
|
|||
|
|
|||
|
IrContents >>= 2;
|
|||
|
|
|||
|
for (i = 2; i < 10; i++) {
|
|||
|
|
|||
|
if (IrContents & 0x1) {
|
|||
|
|
|||
|
InterruptVector = i + CORELLE_INTERRUPT2_OFFSET;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IrContents >>= 1;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return (InterruptVector);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpAcknowledgeClockInterrupt(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Acknowledge the clock interrupt from the interval timer. The interval
|
|||
|
timer for Mikasa comes from a Dallas real-time clock.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Acknowledge the clock interrupt by reading the control register C of
|
|||
|
// the Real Time Clock.
|
|||
|
//
|
|||
|
|
|||
|
HalpReadClockRegister( RTC_CONTROL_REGISTERC );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|