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

2365 lines
54 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:
rwintsup.c
Abstract:
The module provides the interrupt support for Rawhide systems.
Author:
Eric Rehm (DEC) 29-December-1993
Revision History:
Eric Rehm (DEC) 26-July-1994
Adapted from Alcor module for Rawhide.
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
#include "eisa.h"
#include "ebsgdma.h"
#include "rawhide.h"
#include "pintolin.h"
extern IOD_REGISTER_CLASS DumpIodFlag;
//
// Declare the interrupt structures and spinlocks for the intermediate
// interrupt dispatchers.
//
KINTERRUPT HalpPciInterrupt;
KINTERRUPT HalpEisaInterrupt;
extern BOOLEAN HalpLogCorrectableErrors;
//
// The enable mask for all interrupts sourced from the IOD (all device
// interrupts, and all from PCI). A "1" indicates the interrupt is enabled.
//
ULONG HalpIodInterruptMask[RAWHIDE_MAXIMUM_PCI_BUS][2] = {0};
//
// Define the context structure for use by interrupt service routines.
//
typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
PKINTERRUPT InterruptObject,
PVOID ServiceContext,
PKTRAP_FRAME TrapFrame
);
//
// Declare the interrupt handler for the EISA bus. The interrupt dispatch
// routine, HalpEisaDispatch, is called from this handler.
//
BOOLEAN
HalpEisaInterruptHandler(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
);
//
// 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;
//
// 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
);
//
// The following functions handle the PCI interrupts.
//
VOID
HalpInitializeIodInterrupts(
MC_DEVICE_ID McDeviceId,
ULONG PciBusNumber,
va_list Arguments
);
VOID
HalpDisablePciInterrupt(
IN ULONG Vector
);
VOID
HalpEnablePciInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
);
BOOLEAN
HalpDeviceDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext,
IN PKTRAP_FRAME TrapFrame
);
//
// Private prototypes
VOID
HalpRawhideDecodePciVector(
IN ULONG PciVector,
OUT PULONG PciBusNumber,
OUT PULONG InterruptLine
);
ULONG
HalpGetRawhidePciInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
/*++
Routine Description:
This function returns the system interrupt vector and IRQL level
corresponding to the specified PCI bus interrupt level and/or vector.
PCI vectors for rawhide are allocated starting with vector 0x40.
Vectors are assigned using the BusInterruptVector and the HwBusNumber.
One execption to this is NCR810 SCSI on PCI bus 1, which is always
allocated vector 0x32.
The HwBusNumber is encoded in the PCI vector by allocating vectors
in blocks of 16 (each IOD supports 16 PCI vectors) as shown below.
RawhidePciVectors:
0x40 |-------------------|
| PCI 0 vectors |
|-------------------|
0x50 | PCI 1 vectors |
|-------------------|
.
.
PCI interrupt routines may use the vector assigned to obtain the
PCI bus number and IRR bit as follows.
PciBus = (Vector - RawhidePciVectors) / 0x10
IrrBitShift = (Vector - RawhidePciVectors) % 0x10
Arguments:
BusHandler - Supplies a pointer to the bus handler of the bus that
needs a system interrupt vector.
RootHandler - Supplies a pointer to the bus handler of the root
bus for the bus represented by BusHandler.
BusInterruptLevel - Supplies the bus-specific interrupt level.
BusInterruptVector - Supplies the bus-specific interrupt vector
assigned to the device during PCI configuration
using the Pin-to-line table.
Irql - Returns the system request priority.
Affinity - Returns the affinity for the requested vector
Return Value:
Returns the system interrupt vector corresponding to the PCI device.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IntMask;
IOD_INT_TARGET_DEVICE IntTarg;
PIOD_VECTOR_DATA IodVectorData;
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
ULONG LogicalProcessor;
ULONG TargetCpu;
ULONG MaskBit;
ULONG PciVector;
ULONG PciBusNumber;
ULONG InterruptLine;
//
// NCR 810 on Bus 1 is a special case
//
if ( (BusInterruptVector == RawhideNcr810PinToLine) &&
(BusData->HwBusNumber == 1) ) {
PciVector = RawhideScsiVector;
} else {
#if HALDBG
DbgPrint(
"HalpGetRawhidePciInterruptVector: Bus %d\n",
BusData->HwBusNumber
);
#endif
//
// Build the rawhide vector.
//
PciVector = RawhidePciVectors;
PciVector += (BusData->HwBusNumber << 4);
//
// BusInterruptVectors are numbered 1-16, so
// subtract one to convert to table offset.
//
PciVector += (BusInterruptVector - 1);
//
// Rawhide Pin2Line table entries contain an arbitrary offset
// so that PCI InterruptLine values don't appear to conflict
// with EISA/ISA vectors reported by WINMSD.
//
PciVector -= RawhidePinToLineOffset;
}
//
// Decode the PCI bus number and interrupt line from the Vector
//
HalpRawhideDecodePciVector(PciVector, &PciBusNumber, &InterruptLine);
#if HALDBG
DbgPrint(
"Vector 0x%x maps to PCI %d, InterruptLine %d\n",
PciVector,
PciBusNumber,
InterruptLine
);
#endif
//
// Determine which IOD this interrupt is assigned to
// and obtain the IOD's geographic address.
//
McDeviceId = HalpIodLogicalToPhysical[PciBusNumber];
//
// Determine the IRR bit
//
MaskBit = (ULONG) 1<< InterruptLine;
//
// Obtain the IOD vector table entry
//
IodVectorData = HalpIodVectorData + PciBusNumber;
//
// Assign this vector to a CPU. This will update the target
// mask for this IOD as a side effect.
//
TargetCpu = HalpAssignInterruptForIod(IodVectorData, MaskBit);
#if HALDBG
DbgPrint("HalpGetRawhidePCIVector: CPU %d\n", TargetCpu);
#endif
//
// Assign affinity for all processors. This will cause
// the kernel to add an IDT entry for all processors.
// This is necessary if we are going to dynamically
// reassign the interrupt to a different processor at
// a later time.
//
*Irql = DEVICE_HIGH_LEVEL;
*Affinity = (1 << TargetCpu);
#if HALDBG
DbgPrint(
"HalpGetRawhidePCIVector: vector 0x%x, Iqrl 0x%x, Affinity 0x%x\n",
PciVector,
*Irql,
*Affinity
);
#endif
return ( PciVector );
}
ULONG
HalpGetRawhideEisaInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
/*++
Routine Description:
This function returns the system interrupt vector and IRQL level
corresponding to the specified Eisa/Isa interrupt level and/or vector.
Eisa vectors for rawhide are allocated starting at vector 0x20.
Vectors are assigned using the BusInterruptLevel.
Arguments:
BusHandler - Supplies a pointer to the bus handler of the bus that
needs a system interrupt vector.
RootHandler - Supplies a pointer to the bus handler of the root
bus for the bus represented by BusHandler.
BusInterruptLevel - Supplies the bus-specific interrupt level.
BusInterruptVector - Supplies the bus-specific interrupt vector.
Irql - Returns the system request priority.
Affinity - Returns the affinity for the requested vector
Return Value:
Returns the system interrupt vector corresponding to the specified device.
--*/
{
ULONG EisaVector;
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
//
// Build the Eisa/Isa vector
//
EisaVector = RawhideEisaVectors;
EisaVector += BusInterruptLevel;
//
// Assign affinity for all processors. This will cause
// the kernel to add an IDT entry for all processors.
// This is necessary if we are going to dynamically
// reassign the interrupt to a different processor at
// a later time.
//
*Irql = DEVICE_HIGH_LEVEL;
*Affinity = (1 << HAL_PRIMARY_PROCESSOR);
return ( EisaVector );
}
ULONG
HalpGetRawhideInternalInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
/*++
Routine Description:
This function returns the system interrupt vector and IRQL level
corresponding to the specified Internal Bus interrupt level.
Vectors are assigned using the BusInterruptLevel.
Arguments:
BusHandler - Supplies a pointer to the bus handler of the bus that
needs a system interrupt vector.
RootHandler - Supplies a pointer to the bus handler of the root
bus for the bus represented by BusHandler.
BusInterruptLevel - Supplies the bus-specific interrupt level.
BusInterruptVector - Supplies the bus-specific interrupt vector.
Irql - Returns the system request priority.
Affinity - Returns the affinity for the requested vector
Return Value:
Returns the system interrupt vector corresponding to the specified device.
--*/
{
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
PIOD_VECTOR_DATA IodVectorData;
ULONG InternalVector;
ULONG TargetCpu;
ULONG MaskBit;
//
// Build the Eisa/Isa vector
//
InternalVector = RawhideInternalBusVectors;
InternalVector += BusInterruptLevel;
//
// The Soft Error has already been assigned
// to the primary processor.
//
if (InternalVector == RawhideSoftErrVector) {
TargetCpu = HAL_PRIMARY_PROCESSOR;
}
//
// The only other Internal device support by
// Rawhide is the I2c bus. This reside on PCI0.
//
else {
//
// Map the vector to an interrupt line.
//
switch (InternalVector) {
case RawhideI2cCtrlVector:
MaskBit = IodI2cCtrlIntMask;
break;
case RawhideI2cBusVector:
MaskBit = IodI2cBusIntMask;
break;
}
//
// Obtain PCI0 vector data
//
IodVectorData = HalpIodVectorData;
//
// Assign this vector to a CPU. This will update the target
// mask for this IOD as a side effect.
//
TargetCpu = HalpAssignInterruptForIod(IodVectorData, MaskBit);
#if HALDBG
DbgPrint("HalpGetRawhideInternalVector: CPU %d\n", TargetCpu);
#endif
}
//
// Assign the vector affinity.
//
*Irql = DEVICE_HIGH_LEVEL;
*Affinity = (1 << TargetCpu);
#if HALDBG
DbgPrint(
"HalpGetRawhideInternalVector: vector 0x%x, Iqrl 0x%x, Affinity 0x%x\n",
InternalVector,
*Irql,
*Affinity
);
#endif
return ( InternalVector );
}
BOOLEAN
HalpInitializeRawhideInterrupts (
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 Rawhide ESC's interrupt controller is
compatible with the EISA interrupt contoller 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();
(PVOID) HalpPCIPinToLineTable = (PVOID) RawhidePCIPinToLineTable;
//
// Intitialize interrupt controller
//
KeRaiseIrql(DEVICE_HIGH_LEVEL, &oldIrql);
//
// Initialize the ESC's PICs for EISA interrupts.
//
HalpInitializeEisaInterrupts();
//
// Initialize the interrupt request masks for all IOD's
//
HalpMcBusEnumAndCall(HalpIodMask, HalpInitializeIodInterrupts);
#if HALDBG
DumpAllIods(DumpIodFlag);
#endif
//
// 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);
}
VOID
HalpInitializeNMI(
VOID
)
/*++
Routine Description:
This function is called to intialize ESC NMI interrupts.
Rawhide uses the Axp legacy ESC NMI vector.
Arguments:
None.
Return Value:
None.
--*/
{
UCHAR DataByte;
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IodIntMask;
//
// 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.
//
DataByte = 0;
WRITE_PORT_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
DataByte
);
}
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;
StatusByte =
READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
if (StatusByte & 0x80) {
HalDisplayString ("NMI: Parity Check / Parity Error\n");
}
if (StatusByte & 0x40) {
HalDisplayString ("NMI: Channel Check / IOCHK\n");
}
KeBugCheck(NMI_HARDWARE_FAILURE);
return(TRUE);
}
VOID
HalpInitializeIodInterrupts(
MC_DEVICE_ID McDeviceId,
ULONG PciBusNumber,
va_list Arguments
)
/*++
Routine Description:
This enumeration routine is called during Phase 0 to assign the
Rawhide Error interrupts for the corresponding IOD to the Primary CPU.
The interrupts
are initialized as follows:
PCI - disabled
HardErr - DISABLED!!! //ecrfix enabled
SoftErr - disabled
Eisa - enabled (Bus 0 only)
EisaNmi - enabled (Bus 0 only)
I2c - disabled (Bus 0 only)
The logical bus is assigned from the static variable PciBusNumber, which is
incremented with each invokation.
Arguments:
McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized
PciBusNumber - Logical (Hardware) PCI Bus number.
Arguments - Variable Arguments. None for this routine.
Return Value:
None.
--*/
{
IOD_INT_MASK IntMask;
PVOID IntMaskQva;
ULONG Target;
//
// Disable MCI bus interrupts
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl,
(IOD_INT_CTL_DISABLE_IO_INT | IOD_INT_CTL_DISABLE_VECT_WRITE)
);
//
// Clear all pending interrupts for this IOD
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntAck0,
0x0
);
//
// Clear interrupt request register (New for CAP Rev2.3)
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntReq,
IodIntMask
);
//
// Clear all pending EISA interrupts for IOD 0
//
if (PciBusNumber == 0) {
INTERRUPT_ACKNOWLEDGE((PVOID)IOD_PCI0_IACK_QVA);
}
// mdbfix - For now, target0 = CPU0, target1 = CPU1
//
// Write the target register.
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg,
HalpLogicalToPhysicalProcessor[0].all
);
//
// Write the mask bits for target 0 and 1
//
for (Target = 0; Target < 2; Target++) {
//
// Obtain the target IRR QVA
//
if (Target) {
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1;
} else {
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0;
}
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
//
// Initialize HardErr for all buses, but Eisa and EisaNmi
// only for Bus 0
//
if (PciBusNumber == 0) {
IntMask.all =
IodHardErrIntMask | IodSoftErrIntMask |
IodEisaIntMask |IodEisaNmiIntMask;
} else {
IntMask.all = IodHardErrIntMask | IodSoftErrIntMask;
}
if (Target ) {
IntMask.all = 0;
}
WRITE_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva,
IntMask.all
);
HalpIodInterruptMask[PciBusNumber][Target] = IntMask.all;
}
//
// Enable Interrupts.
//
WRITE_IOD_REGISTER_NEW(
McDeviceId,
&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl,
(IOD_INT_CTL_ENABLE_IO_INT | IOD_INT_CTL_ENABLE_VECT_WRITE)
);
}
VOID
HalpRawhideDecodePciVector(
IN ULONG PciVector,
OUT PULONG PciBusNumber,
OUT PULONG InterruptLine
)
/*++
Routine Description:
This decodes a PCI vector to obtain the PCI hardware bus number
and the InterruptLine.
Arguments:
PciVector - Supplies the vector of the PCI interrupt that is disabled.
PciBusNumber - IOD number encoded in vector
InterruptLine - IRR interrupt bit number encoded in vector
Return Value:
The PCI bus number and interrupt line are returned.
--*/
{
//
// Special case for NCR810 vector
//
if (PciVector == RawhideScsiVector) {
*PciBusNumber = RAWHIDE_SCSI_PCI_BUS;
*InterruptLine = IodScsiIrrBit;
} else {
//
// Extract the Pci bus number and Interrupt line from the vector
//
PciVector -= RawhidePciVectors;
*PciBusNumber = PciVector / IOD_PCI_VECTORS;
*InterruptLine = PciVector % IOD_PCI_VECTORS;
}
}
VOID
HalpDisablePciInterrupt(
IN ULONG Vector
)
/*++
Routine Description:
This function disables the PCI interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the PCI interrupt that is disabled.
Return Value:
None.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IntMask;
PIOD_VECTOR_DATA IodVectorData;
PVOID IntMaskQva;
ULONG PciBusNumber;
ULONG InterruptLine;
ULONG MaskBit;
ULONG Target = 0;
//
// Decode the PCI bus number and interrupt line from the vector
//
HalpRawhideDecodePciVector(Vector, &PciBusNumber, &InterruptLine);
//
// Determine which IOD this interrupt is assigned to
// and obtain the IOD's geographic address.
//
McDeviceId = HalpIodLogicalToPhysical[PciBusNumber];
//
// Determine the IRR bit
//
MaskBit = ~(1 << InterruptLine);
//
// Obtain the IOD vector table entry
//
IodVectorData = HalpIodVectorData + PciBusNumber;
//
// Determine the target CPU for this vector and
// obtain the cooresponding IntMask QVA
//
if (IodVectorData->IntMask[0].all & MaskBit) {
Target = 0;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0;
} else if (IodVectorData->IntMask[1].all & MaskBit) {
Target = 1;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1;
} else {
#if HALDBG
DbgPrint("HalpDisablePciInterrupt: Vector not assigned target\n");
#endif
return;
}
#if HALDBG
DbgPrint("HalpDisablePciInterrupt: Target %d\n", Target);
#endif
//
// Unassign this vector in the IOD vector data
//
IodVectorData->IntMask[Target].all &= MaskBit;
//
// Decrement CPU vector weight
//
IodVectorData->TargetCpu[Target]->ListEntry.Weight--;
//
// Get the current state of the interrupt mask register, then clear
// the bit corresponding to the adjusted value of Vector to zero,
// to disable that PCI interrupt.
//
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
#if HALDBG
DbgPrint("HalpDisablePCIVector: IntMask(before) 0x%x\n", IntMask);
#endif
IntMask.all &= MaskBit;
WRITE_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva,
IntMask.all
);
#if HALDBG
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
DbgPrint("HalpDisablePCIVector: IntMask(after) 0x%x\n", IntMask);
#endif
//
// Turn off this interrupt in the software mask
//
HalpIodInterruptMask[PciBusNumber][Target] &= MaskBit;
}
VOID
HalpEnablePciInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function enables the PCI interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the PCI interrupt that is enabled.
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
Latched (ignored for Rawhide PCI interrupts; they're always levels).
Return Value:
None.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IntMask;
IOD_INT_TARGET_DEVICE IntTarg;
PIOD_VECTOR_DATA IodVectorData;
PVOID IntMaskQva;
ULONG PciBusNumber;
ULONG InterruptLine;
ULONG MaskBit;
ULONG Affinity;
ULONG Target = 0;
#if HALDBG
DbgPrint(
"HalpEnablePciInterrupt: Vector 0x%x, Mode 0x%x\n",
Vector,
InterruptMode
);
#endif
//
// The kernel will call this routine on the processor
// who will receive the interrupt
//
Affinity = ( 1 << PCR->Prcb->Number);
//
// Decode the PCI bus number and interrupt line from the Vector
//
HalpRawhideDecodePciVector(Vector, &PciBusNumber, &InterruptLine);
#if HALDBG
DbgPrint(
"Vector 0x%x maps to PCI %d, InterruptLine %d\n",
Vector,
PciBusNumber,
InterruptLine
);
#endif
//
// Determine which IOD this interrupt is assigned to
// and obtain the IOD's geographic address.
//
McDeviceId = HalpIodLogicalToPhysical[PciBusNumber];
//
// Determine the IRR bit
//
MaskBit = (ULONG) 1<< InterruptLine;
//
// Obtain the IOD vector table entry
//
IodVectorData = HalpIodVectorData + PciBusNumber;
//
// Obtain the Target CPU
//
if (IodVectorData->Affinity[0] == Affinity) {
Target = 0;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0;
} else {
Target = 1;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1;
}
//
// Handle the case where another device shares this interrupt line.
//
if ( HalpIodInterruptMask[PciBusNumber][Target] & MaskBit) {
#if HALDBG
DbgPrint("Vector 0x%x already assigned\n", Vector);
#endif
return;
}
//
// Get the current state of the interrupt mask register, then set
// the bit corresponding to the adjusted value of Vector to zero,
// to enable that PCI interrupt.
//
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
#if HALDBG
DbgPrint("HalpEnablePCIVector: IntMask(before) 0x%x\n", IntMask);
#endif
IntMask.all |= MaskBit;
WRITE_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva,
IntMask.all
);
#if HALDBG
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
DbgPrint("HalpEnablePCIVector: IntMask(after) 0x%x\n", IntMask);
#endif
#if HALDBG
DumpAllIods(DumpIodFlag & IodInterruptRegisters);
#endif
HalpIodInterruptMask[PciBusNumber][Target] |= MaskBit;
#if HALDBG
DbgPrint(
"HalpEnablePCIVector: Software Mask 0x%x\n",
HalpIodInterruptMask[PciBusNumber][Target]
);
#endif
}
VOID
HalpDisableInternalInterrupt(
IN ULONG Vector
)
/*++
Routine Description:
This function disables the Internal Bus interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the Internal Bus interrupt to disabled.
Return Value:
None.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IntMask;
PIOD_VECTOR_DATA IodVectorData;
PVOID IntMaskQva;
ULONG PciBusNumber;
ULONG InterruptLine;
ULONG MaskBit;
ULONG Target = 0;
//
// Do not physically disable the Soft Error Vector because
// the HAL Correctable Error Handler must execute when
// a Soft Error occurs for system integrity.
//
if (Vector == RawhideSoftErrVector) {
HalpLogCorrectableErrors = FALSE;
return;
}
//
// Map the vector to an interrupt line.
//
switch (Vector) {
case RawhideI2cCtrlVector:
//
// I2C ctrl interrupt on PCI0
//
PciBusNumber = 0;
MaskBit = IodI2cCtrlIntMask;
break;
case RawhideI2cBusVector:
//
// I2C bus interrupt on PCI0
//
PciBusNumber = 0;
MaskBit = IodI2cBusIntMask;
break;
default:
return;
}
//
// Obtain the IOD geographic address for the PCI bus.
//
McDeviceId = HalpIodLogicalToPhysical[PciBusNumber];
//
// Obtain the IOD vector data for the PCI bus.
//
IodVectorData = HalpIodVectorData + PciBusNumber;
//
// Determine the target CPU for this vector and
// obtain the cooresponding IntMask QVA
//
if (IodVectorData->IntMask[0].all & MaskBit) {
Target = 0;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0;
} else if (IodVectorData->IntMask[1].all & MaskBit) {
Target = 1;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1;
} else {
#if HALDBG
DbgPrint("HalpDisablePciInterrupt: Vector not assigned target\n");
#endif
return;
}
#if HALDBG
DbgPrint("HalpDisableInteralInterrupt: Target %d\n", Target);
#endif
//
// Unassign this vector in the IOD vector data
//
IodVectorData->IntMask[Target].all &= ~MaskBit;
//
// Decrement CPU vector weight
//
IodVectorData->TargetCpu[Target]->ListEntry.Weight--;
//
// Get the current state of the interrupt mask register, then clear
// the bit corresponding to the adjusted value of Vector to zero,
// to disable that PCI interrupt.
//
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
#if HALDBG
DbgPrint("HalpEnablePCIVector: IntMask(before) 0x%x\n", IntMask);
#endif
IntMask.all &= ~MaskBit;
WRITE_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva,
IntMask.all
);
#if HALDBG
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
DbgPrint("HalpEnablePCIVector: IntMask(after) 0x%x\n", IntMask);
#endif
//
// Turn off this interrupt in the software mask
//
HalpIodInterruptMask[PciBusNumber][Target] &= ~MaskBit;
}
VOID
HalpEnableInternalInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function enables the Internal Bus interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the Internal Bus interrupt that is enabled.
InterruptMode - Ignored. Rawhide device interrupts level sensitive.
Return Value:
None.
--*/
{
MC_DEVICE_ID McDeviceId;
IOD_INT_MASK IntMask;
IOD_INT_TARGET_DEVICE IntTarg;
PIOD_VECTOR_DATA IodVectorData;
PVOID IntMaskQva;
ULONG PciBusNumber;
ULONG InterruptLine;
ULONG MaskBit;
ULONG Affinity;
ULONG Target = 0;
//
// Do not physically disable the Soft Error Vector because
// the HAL Correctable Error Handler must execute when
// a Soft Error occurs for system integrity.
//
if (Vector == RawhideSoftErrVector) {
HalpLogCorrectableErrors = TRUE;
return;
}
//
// The kernel will call this routine on the processor
// who will receive the interrupt
//
Affinity = ( 1 << PCR->Prcb->Number);
//
// Map the vector to an interrupt line.
//
switch (Vector) {
case RawhideI2cCtrlVector:
//
// I2C ctrl interrupt on PCI0
//
PciBusNumber = 0;
MaskBit = IodI2cCtrlIntMask;
break;
case RawhideI2cBusVector:
//
// I2C ctrl interrupt on PCI0
//
PciBusNumber = 0;
MaskBit = IodI2cBusIntMask;
break;
default:
return;
}
#if HALDBG
DbgPrint(
"HalpEnableInternalInterrupt: Vector 0x%x, Mode 0x%x\n",
Vector,
InterruptMode
);
#endif
#if HALDBG
DbgPrint(
"Vector 0x%x maps to PCI %d, InterruptLine %d\n",
Vector,
0,
MaskBit
);
#endif
//
// Obtain the IOD geographic address for the PCI bus.
//
McDeviceId = HalpIodLogicalToPhysical[PciBusNumber];
//
// Obtain the IOD vector table entry for the PCI bus.
//
IodVectorData = HalpIodVectorData + PciBusNumber;
//
// Determine the target CPU for this vector and
// obtain the cooresponding IntMask QVA
//
if (IodVectorData->Affinity[0] == Affinity) {
Target = 0;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask0;
} else {
Target = 1;
IntMaskQva = (PVOID)&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntMask1;
}
//
// Get the current state of the interrupt mask register, then set
// the bit corresponding to the adjusted value of Vector to zero,
// to enable that PCI interrupt.
//
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
#if HALDBG
DbgPrint("HalpEnableInternalVector: IntMask(before) 0x%x\n", IntMask);
#endif
IntMask.all |= MaskBit;
WRITE_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva,
IntMask.all
);
#if HALDBG
IntMask.all = READ_IOD_REGISTER_NEW(
McDeviceId,
IntMaskQva
);
DbgPrint("HalpEnableInternalVector: IntMask(after) 0x%x\n", IntMask);
#endif
#if HALDBG
DumpAllIods(DumpIodFlag & IodInterruptRegisters);
#endif
HalpIodInterruptMask[PciBusNumber][Target] |= MaskBit;
#if HALDBG
DbgPrint(
"HalpEnableInternalVector: Software Mask 0x%x\n",
HalpIodInterruptMask[PciBusNumber][Target]
);
#endif
}
#if HALDBG
ULONG DeviceDispatchFlag = 0;
#define DispatchPrint(_X_)\
{ \
if (DeviceDispatchFlag) DbgPrint _X_; \
} \
#else
#define DispatchPrint(_X_)
#endif
#ifdef FORCE_CORRECTABLE_ERROR
ULONG DispatchSoftError = 0;
#endif // FORCE_CORRECTABLE_ERROR
#ifndef POSTED
BOOLEAN
HalpDeviceDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This routine is entered as the result of an interrupt being generated
via the vector that is connected to an interrupt object associated with
the PCI 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.
--*/
{
PULONG DispatchCode;
PKINTERRUPT InterruptObject;
IOD_POSTED_INTERRUPT IntReq;
MC_ENUM_CONTEXT mcCtx;
ULONG PciIdtIndex;
ULONG VectorShift;
ULONG PciBusNumber;
ULONG Target = 0;
volatile IOD_PCI_REVISION IodRevision;
DispatchPrint(("HalpDeviceDispatch: enter\n"));
//
// Intialize enumerator.
//
HalpMcBusEnumStart ( HalpIodMask, &mcCtx );
//
// Handle interrupts for each IOD as follows.
//
// 1. read interrupt request register for IOD
// 2. process pending EISA interrupt.
// 3. process all pending PCI interrupts.
// 4. acknowledge the interrupts serviced.
// 5. start over with next IOD.
//
PciBusNumber = 0;
while ( HalpMcBusEnum( &mcCtx ) ) {
//
// Read in the interrupt register.
//
IntReq.all = READ_IOD_REGISTER_NEW(
mcCtx.McDeviceId,
&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntReq);
DispatchPrint((
"HalpDeviceDispatch: IOD 0x%x, IRR 0x%x\n",
mcCtx.McDeviceId.all,
IntReq.all
));
// mdbfix - is this really necessary?
//
// Consider only those interrupts which are currently enabled.
//
#if HALDBG
if ( IntReq.all !=
(IntReq.all & HalpIodInterruptMask[PciBusNumber][Target]) ) {
DispatchPrint((
"HalpDeviceDispatch: IOD (%d, %d), IRR Unmasked 0x%x != IRR Masked 0x%x\n",
mcCtx.McDeviceId.Gid,
mcCtx.McDeviceId.Mid,
IntReq.all,
(IntReq.all & HalpIodInterruptMask[PciBusNumber][Target])
));
}
#endif
IntReq.all &= HalpIodInterruptMask[PciBusNumber][Target];
DispatchPrint((
"HalpDeviceDispatch: IRR masked 0x%x\n",
IntReq.all
));
//
// If no interrupts pending, do not
// send INT ACK and skip to next bus.
//
if (IntReq.all == 0) {
PciBusNumber++;
continue;
}
//
// Handle Error Interrupts
//
if (IntReq.HardErr ) {
//
// Handle hard error interrupt
//
#if HALDBG
DispatchPrint((
"Hard Error Interrupt on IOD (%d, %d)\n",
mcCtx.McDeviceId.Gid,
mcCtx.McDeviceId.Mid
));
#endif // HALDBG
HalpIodHardErrorInterrupt();
}
if ( IntReq.SoftErr ) {
//
// Dispatch Event logging interrupt.
//
#if HALDBG
DispatchPrint((
"Soft Error Interrupt on IOD (%d, %d)\n",
mcCtx.McDeviceId.Gid,
mcCtx.McDeviceId.Mid
));
#endif // HALDBG
#if 1
// mdbfix - until an error log driver exists to connect the
// soft error interrupt, explicitly call the ISR.
HalpIodSoftErrorInterrupt();
#else
DispatchCode =
(PULONG)PCR->InterruptRoutine[RawhideSoftErrVector];
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)
InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
#endif
}
//
// Process PCI interrupts.
//
if ( IntReq.Pci ) {
DispatchPrint((
"HalpDeviceDispatch: PCI interrupt\n", IntReq.all
));
//
// Initialize IDT offset to PCI vectors and obtain
// the vector table section for this PCI bus
//
PciIdtIndex = RawhidePciVectors + (PciBusNumber << 4);
VectorShift = IntReq.Pci;
while (VectorShift) {
if ( VectorShift & 0x1 ) {
DispatchPrint((
"HalpDeviceDispatch: Dispatch PCI IDT Index %d\n",
PciIdtIndex
));
//
// Map the Interrupt Request Register bit to a vector
//
DispatchCode = (PULONG)PCR->InterruptRoutine[PciIdtIndex];
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
//
// Try next vector
//
PciIdtIndex++;
VectorShift = VectorShift >> 1;
} //end while(VectorShift);
} //end if(IntReq.Pci);
//
// Handle bus 0 specific interrupts
//
if ( PciBusNumber == 0 ) {
if ( IntReq.Eisa ) {
//
// EISA interrupt. Call HalpEisaDispatch.
//
HalpEisaDispatch(
Interrupt,
(PVOID)IOD_PCI0_IACK_QVA,
TrapFrame
);
}
if (IntReq.I2cBus) {
//
// I2c Bus Vector
//
DispatchCode =
(PULONG)PCR->InterruptRoutine[RawhideI2cBusVector] ;
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)
InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
if (IntReq.I2cCtrl) {
//
// I2c Controller Vector
//
DispatchCode =
(PULONG)PCR->InterruptRoutine[RawhideI2cCtrlVector] ;
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)
InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
}
//
// Handle NCR810 for PCI bus 1
//
if ( ( PciBusNumber == 1 ) && ( IntReq.Ncr810 ) ) {
DispatchCode = (PULONG)PCR->InterruptRoutine[RawhideScsiVector];
InterruptObject = CONTAINING_RECORD( DispatchCode,
KINTERRUPT,
DispatchCode );
((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame );
}
//
// Acknowledge after All pending interrupts serviced for this IOD
// for UP interrupt scheme, all Interrupts routed to targe 0.
//
WRITE_IOD_REGISTER_NEW(
mcCtx.McDeviceId,
&((PIOD_INT_CSRS)IOD_INT_CSRS_QVA)->IntAck0,
0x0
);
//
// ecrfix - Read the IOD revision to force the write.
//
IodRevision.all =
READ_IOD_REGISTER_NEW(
mcCtx.McDeviceId,
&((PIOD_GENERAL_CSRS)(IOD_GENERAL_CSRS_QVA))->PciRevision );
//
// Next PCI bus number
//
PciBusNumber++;
} //end while (HalpMcBusEnum())
return TRUE;
}
#else // POSTED
BOOLEAN
HalpDeviceDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This routine is entered as the result of an interrupt being generated
via the vector that is connected to an interrupt object associated with
the PCI 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.
--*/
{
PULONG DispatchCode;
PKINTERRUPT InterruptObject;
PIOD_POSTED_INTERRUPT PostedInterrupts;
IOD_POSTED_INTERRUPT IntReq;
MC_DEVICE_ID McDeviceId;
PKPRCB Prcb;
PVOID IodAckQva;
ULONG PciIdtIndex;
ULONG VectorShift;
ULONG PciBusNumber;
ULONG Target = 0;
volatile IOD_PCI_REVISION IodRevision;
Prcb = PCR->Prcb;
PciIdtIndex = RawhidePciVectors;
//
// Obtain the processor area in IOD vector table
// and the IOD service mask.
//
PostedInterrupts = (PIOD_POSTED_INTERRUPT) HAL_PCR->PostedInterrupts;
DispatchPrint((
"DeviceDispatch: enter, IodVectorTable 0x%x\n",
PostedInterrupts
));
//
// Handle interrupts for each IOD as follows.
//
// 1. read the interrupt vector table entry.
// 2. process pending EISA interrupt.
// 3. process all pending PCI interrupts.
// 4. acknowledge the interrupts serviced.
// 5. start over with next IOD.
//
for ( PciBusNumber = 0;
PciBusNumber < HalpNumberOfIods;
PciBusNumber++, PostedInterrupts++) {
DispatchPrint((
"DeviceDispatch: IntReq: 0x%x\n\tTarget: %d\n\tDevice: (%d, %d)",
PostedInterrupts->IntReq,
PostedInterrupts->Target,
(PostedInterrupts->McDevId >> 0x3) & 0x7,
PostedInterrupts->McDevId & 0x7
));
//
// Perform a passive release.
//
if (PostedInterrupts->Valid && (PostedInterrupts->IntReq == 0) ) {
IntReq.all = PostedInterrupts->IntReq;
McDeviceId.all = PostedInterrupts->McDevId;
Target = PostedInterrupts->Target;
//
// Invalidate this entry to prevent the next device interrupt
// dispatch from using stale information. We must do this
// before the ACK, which allows the IOD to post.
//
PostedInterrupts->all = 0;
IOD_INTERRUPT_ACKNOWLEDGE(McDeviceId, Target);
//
// Skip to check next vector
//
continue;
}
if (PostedInterrupts->Valid && PostedInterrupts->IntReq) {
DispatchPrint((
"DeviceDispatch: Interrupt(s) Pending on PCI bus %d\n",
PciBusNumber
));
IntReq.all = PostedInterrupts->IntReq;
McDeviceId.all = PostedInterrupts->McDevId;
Target = PostedInterrupts->Target;
DispatchPrint((
"DeviceDispatch: IodVectorTable\n\tIntReq: 0x%x\n\tTarget: %d\n\tDevice: (%d, %d)",
PostedInterrupts->IntReq,
PostedInterrupts->Target,
McDeviceId.Gid,
McDeviceId.Mid
));
//
// Consider only those interrupts which are currently enabled.
//
IntReq.all &= HalpIodInterruptMask[PciBusNumber][Target];
DispatchPrint((
"DeviceDispatch: IntReq (masked) 0x%x\n",
IntReq.all
));
//
// Handle Error Interrupts
//
if (IntReq.HardErr ) {
//
// Handle hard error interrupt
//
DispatchPrint((
"Hard Error Interrupt on IOD (%d, %d)\n",
McDeviceId.Gid,
McDeviceId.Mid
));
HalpIodHardErrorInterrupt();
}
if ( IntReq.SoftErr ) {
//
// Dispatch Event logging interrupt.
//
DispatchPrint((
"Soft Error Interrupt on IOD (%d, %d)\n",
McDeviceId.Gid,
McDeviceId.Mid
));
HalpIodSoftErrorInterrupt();
}
#ifdef FORCE_CORRECTABLE_ERROR
if ( (PCR->Number == HAL_PRIMARY_PROCESSOR) &&
DispatchSoftError ) {
DispatchSoftError = 0;
HalpIodSoftErrorInterrupt();
}
#endif // FORCE_CORRECTABLE_ERROR
//
// Process PCI interrupts.
//
if ( IntReq.Pci ) {
DispatchPrint((
"HalpDeviceDispatch: PCI interrupt\n", IntReq.all
));
//
// Initialize IDT offset to PCI vectors and obtain
// the vector table section for this PCI bus
//
PciIdtIndex = RawhidePciVectors + (PciBusNumber << 4);
VectorShift = IntReq.Pci;
while (VectorShift) {
if ( VectorShift & 0x1 ) {
DispatchPrint((
"HalpDeviceDispatch: Dispatch PCI IDT Index %d\n",
PciIdtIndex
));
//
// Map the Interrupt Request Register bit to a vector
//
DispatchCode = (PULONG)PCR->InterruptRoutine[PciIdtIndex];
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
//
// Try next vector
//
PciIdtIndex++;
VectorShift = VectorShift >> 1;
} //end while(VectorShift);
} //end if(IntReq.Pci);
//
// Handle bus 0 specific interrupts
//
if ( PciBusNumber == 0 ) {
if ( IntReq.Eisa ) {
//
// EISA interrupt. Call HalpEisaDispatch.
//
HalpEisaDispatch(
Interrupt,
(PVOID)IOD_PCI0_IACK_QVA,
TrapFrame
);
}
//
// Handle I2c Bus Vector
//
if (IntReq.I2cBus) {
DispatchCode =
(PULONG)PCR->InterruptRoutine[RawhideI2cBusVector] ;
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)
InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
//
// Handle I2c Controller Vector
//
if (IntReq.I2cCtrl) {
DispatchCode =
(PULONG)PCR->InterruptRoutine[RawhideI2cCtrlVector] ;
InterruptObject = CONTAINING_RECORD(
DispatchCode,
KINTERRUPT,
DispatchCode
);
((PSECOND_LEVEL_DISPATCH)
InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame
);
}
}
//
// Handle NCR810 for PCI bus 1
//
if ( ( PciBusNumber == 1 ) && ( IntReq.Ncr810 ) ) {
DispatchCode = (PULONG)PCR->InterruptRoutine[RawhideScsiVector];
InterruptObject = CONTAINING_RECORD( DispatchCode,
KINTERRUPT,
DispatchCode );
((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
InterruptObject,
InterruptObject->ServiceContext,
TrapFrame );
}
//
// Invalidate this entry to prevent the next device interrupt
// dispatch from using stale information. We must do this
// before the ACK, which allows the IOD to post.
//
PostedInterrupts->all = 0;
//
// Acknowledge the interrupt
//
IOD_INTERRUPT_ACKNOWLEDGE(McDeviceId, Target);
} //end if (PostedInterrupts.Valid && PostedInterrupts.IntReq)
} //end for
return TRUE;
}
#endif //POSTED
VOID
HalpAcknowledgeIpiInterrupt(
VOID
)
/*++
Routine Description:
Acknowledge the interprocessor interrupt on the current processor.
Arguments:
None.
Return Value:
None.
--*/
{
PIOD_GENERAL_CSRS IodGeneralCsrs;
IOD_WHOAMI IodWhoAmI;
MC_ENUM_CONTEXT mcCtx;
MC_DEVICE_ID McDeviceId;
volatile IOD_PCI_REVISION IodRevision;
PKPRCB Prcb;
//
// Avoid a WhoAmI register read by using the PCR
//
Prcb = PCR->Prcb;
McDeviceId.all = HalpLogicalToPhysicalProcessor[Prcb->Number].all;
//
// Acknownledge the ip interrupt by writing to our own
// ip interrupt acknowledge.
//
IP_INTERRUPT_ACKNOWLEDGE( McDeviceId );
return;
}