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;
|
||
}
|
||
|