2365 lines
54 KiB
C
2365 lines
54 KiB
C
/*++
|
||
|
||
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;
|
||
|
||
}
|