NT4/private/ntos/nthals/halpinna/alpha/mkintsup.c
2020-09-30 17:12:29 +02:00

1076 lines
26 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.

/*++
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;
}